29
29
n propeller revolution (rpm) ]
30
30
31
31
u = depthHeadingAutopilot(eta,nu,sampleTime)
32
- Simultaneously control of depth and heading using two controllers of
33
- PID type . Propeller rpm is given as a step command.
32
+ Simultaneously control of depth and heading using controllers of
33
+ PID and SMC ype . Propeller rpm is given as a step command.
34
34
35
35
u = stepInput(t) generates tail rudder, stern planes and RPM step inputs.
36
36
48
48
import numpy as np
49
49
import math
50
50
import sys
51
- from python_vehicle_simulator .lib .control import PIDpolePlacement
51
+ from python_vehicle_simulator .lib .control import integralSMC
52
52
from python_vehicle_simulator .lib .gnc import crossFlowDrag ,forceLiftDrag ,Hmtrx ,m2c ,gvect ,ssa
53
53
54
54
# Class Vehicle
@@ -122,11 +122,11 @@ def __init__(
122
122
123
123
124
124
# Actuator dynamics
125
- self .deltaMax_r = 30 * self .D2R # max rudder angle (rad)
126
- self .deltaMax_s = 30 * self .D2R # max stern plane angle (rad)
125
+ self .deltaMax_r = 15 * self .D2R # max rudder angle (rad)
126
+ self .deltaMax_s = 15 * self .D2R # max stern plane angle (rad)
127
127
self .nMax = 1525 # max propeller revolution (rpm)
128
- self .T_delta = 1.0 # rudder/stern plane time constant (s)
129
- self .T_n = 1.0 # propeller time constant (s)
128
+ self .T_delta = 0.1 # rudder/stern plane time constant (s)
129
+ self .T_n = 0.1 # propeller time constant (s)
130
130
131
131
if r_rpm < 0.0 or r_rpm > self .nMax :
132
132
sys .exit ("The RPM value should be in the interval 0-%s" , (self .nMax ))
@@ -187,14 +187,16 @@ def __init__(
187
187
self .w_pitch = math .sqrt ( self .W * ( self .r_bg [2 ]- self .r_bb [2 ] ) /
188
188
self .M [4 ][4 ] )
189
189
190
- # Tail rudder parameters (single)
190
+ S_fin = 0.00665 ; # fin area
191
+
192
+ # Tail rudder parameters
191
193
self .CL_delta_r = 0.5 # rudder lift coefficient
192
- self .A_r = 2 * 0.10 * 0.05 # rudder area (m2)
194
+ self .A_r = 2 * S_fin # rudder area (m2)
193
195
self .x_r = - a # rudder x-position (m)
194
196
195
- # Stern-plane paramaters (double)
197
+ # Stern-plane parameters (double)
196
198
self .CL_delta_s = 0.7 # stern-plane lift coefficient
197
- self .A_s = 2 * 0.10 * 0.05 # stern-plane area (m2)
199
+ self .A_s = 2 * S_fin # stern-plane area (m2)
198
200
self .x_s = - a # stern-plane z-position (m)
199
201
200
202
# Low-speed linear damping matrix parameters
@@ -203,30 +205,40 @@ def __init__(
203
205
self .T_heave = self .T_sway # equal for for a cylinder-shaped AUV
204
206
self .zeta_roll = 0.3 # relative damping ratio in roll
205
207
self .zeta_pitch = 0.8 # relative damping ratio in pitch
206
- self .T_yaw = 5 # time constant in yaw (s)
208
+ self .T_yaw = 1 # time constant in yaw (s)
209
+
210
+ # Feed forward gains (Nomoto gain parameters)
211
+ self .K_nomoto = 5.0 / 20.0 # K_nomoto = r_max / delta_max
212
+ self .T_nomoto = self .T_yaw # Time constant in yaw
207
213
208
- # Heading autopilot
209
- self .wn_psi = 0.5 # PID pole placement parameters
210
- self .zeta_psi = 1
211
- self .r_max = 1 * math .pi / 180 # maximum yaw rate
212
- self .psi_d = 0 # position, velocity and acc. states
214
+ # Heading autopilot reference model
215
+ self .psi_d = 0 # position, velocity and acc. states
213
216
self .r_d = 0
214
217
self .a_d = 0
215
- self .wn_d = self .wn_psi / 5 # desired natural frequency
216
- self .zeta_d = 1 # desired realtive damping ratio
218
+ self .wn_d = 0.1 # desired natural frequency
219
+ self .zeta_d = 1 # desired realtive damping ratio
220
+ self .r_max = 5.0 * math .pi / 180 # maximum yaw rate
221
+
222
+ # Heading autopilot (Equation 16.479 in Fossen 2021)
223
+ # sigma = r-r_d + 2*lambda*ssa(psi-psi_d) + lambda^2 * integral(ssa(psi-psi_d))
224
+ # delta = (T_nomoto * r_r_dot + r_r - K_d * sigma
225
+ # - K_sigma * (sigma/phi_b)) / K_nomoto
226
+ self .lam = 0.1
227
+ self .phi_b = 0.1 # boundary layer thickness
228
+ self .K_d = 0.5 # PID gain
229
+ self .K_sigma = 0.05 # SMC switching gain
217
230
218
231
self .e_psi_int = 0 # yaw angle error integral state
219
232
220
-
221
-
222
233
# Depth autopilot
223
- self .wn_d_z = 1 / 20 # desired natural frequency, reference model
234
+ self .wn_d_z = 0.02 # desired natural frequency, reference model
224
235
self .Kp_z = 0.1 # heave proportional gain, outer loop
225
236
self .T_z = 100.0 # heave integral gain, outer loop
226
- self .Kp_theta = 1.0 # pitch PID controller
227
- self .Kd_theta = 3.0
228
- self .Ki_theta = 0.1
229
-
237
+ self .Kp_theta = 5.0 # pitch PID controller
238
+ self .Kd_theta = 2.0
239
+ self .Ki_theta = 0.3
240
+ self .K_w = 5.0 # optional heave velocity feedback gain
241
+
230
242
self .z_int = 0 # heave position integral state
231
243
self .z_d = 0 # desired position, LP filter initial state
232
244
self .theta_int = 0 # pitch angle integral state
@@ -309,13 +321,17 @@ def dynamics(self, eta, nu, u_actual, u_control, sampleTime):
309
321
# Rigi-body/added mass Coriolis/centripetal matrices expressed in the CO
310
322
CRB = m2c (self .MRB , nu_r )
311
323
CA = m2c (self .MA , nu_r )
312
-
313
- # Nonlinear quadratic velocity terms in pitch and yaw (Munk moments)
314
- # are set to zero since only linear damping is used
315
- CA [4 ][0 ] = 0
324
+
325
+ # CA-terms in roll, pitch and yaw can destabilize the model if quadratic
326
+ # rotational damping is missing. These terms are assumed to be zero
327
+ CA [4 ][0 ] = 0 # Quadratic velocity terms due to pitching
328
+ CA [0 ][4 ] = 0
316
329
CA [4 ][2 ] = 0
317
- CA [5 ][0 ] = 0
330
+ CA [2 ][4 ] = 0
331
+ CA [5 ][0 ] = 0 # Munk moment in yaw
332
+ CA [0 ][5 ] = 0
318
333
CA [5 ][1 ] = 0
334
+ CA [1 ][5 ] = 0
319
335
320
336
C = CRB + CA
321
337
@@ -329,9 +345,9 @@ def dynamics(self, eta, nu, u_actual, u_control, sampleTime):
329
345
self .M [5 ][5 ] / self .T_yaw
330
346
])
331
347
332
- D [ 0 ][ 0 ] = D [ 0 ][ 0 ] * math . exp ( - 3 * U_r ) # For DOF 1,2,6 the D elements
333
- D [1 ][ 1 ] = D [1 ][ 1 ] * math .exp (- 3 * U_r ) # go to zero at higher speeds, i.e.
334
- D [5 ][ 5 ] = D [5 ][ 5 ] * math .exp (- 3 * U_r ) # drag and lift/drag dominate
348
+ # Linear surge and sway damping
349
+ D [0 ][ 0 ] = D [0 ][ 0 ] * math .exp (- 3 * U_r ) # vanish at high speed where quadratic
350
+ D [1 ][ 1 ] = D [1 ][ 1 ] * math .exp (- 3 * U_r ) # drag and lift forces dominates
335
351
336
352
tau_liftdrag = forceLiftDrag (self .diam ,self .S ,self .CD_0 ,alpha ,U_r )
337
353
tau_crossflow = crossFlowDrag (self .L ,self .diam ,self .diam ,nu_r )
@@ -424,6 +440,7 @@ def depthHeadingAutopilot(self, eta, nu, sampleTime):
424
440
z = eta [2 ] # heave position (depth)
425
441
theta = eta [4 ] # pitch angle
426
442
psi = eta [5 ] # yaw angle
443
+ w = nu [2 ] # heave velocity
427
444
q = nu [4 ] # pitch rate
428
445
r = nu [5 ] # yaw rate
429
446
e_psi = psi - self .psi_d # yaw angle tracking error
@@ -446,40 +463,36 @@ def depthHeadingAutopilot(self, eta, nu, sampleTime):
446
463
# PI controller
447
464
theta_d = self .Kp_z * ( (z - self .z_d ) + (1 / self .T_z ) * self .z_int )
448
465
delta_s = - self .Kp_theta * ssa ( theta - theta_d ) - self .Kd_theta * q \
449
- - self .Ki_theta * self .theta_int
466
+ - self .Ki_theta * self .theta_int - self . K_w * w
450
467
451
468
# Euler's integration method (k+1)
452
469
self .z_int += sampleTime * ( z - self .z_d );
453
470
self .theta_int += sampleTime * ssa ( theta - theta_d );
454
471
455
472
#######################################################################
456
- # Heading autopilot (PID controller)
473
+ # Heading autopilot (SMC controller)
457
474
#######################################################################
458
475
459
- wn = self .wn_psi # PID natural frequency
460
- zeta = self .zeta_psi # PID natural relative damping factor
461
476
wn_d = self .wn_d # reference model natural frequency
462
477
zeta_d = self .zeta_d # reference model relative damping factor
463
478
464
- m = self .M [5 ][5 ]
465
- d = 0
466
- k = 0
467
479
468
- # PID feedback controller with 3rd-order reference model
480
+ # Integral SMC with 3rd-order reference model
469
481
[delta_r , self .e_psi_int , self .psi_d , self .r_d , self .a_d ] = \
470
- PIDpolePlacement (
482
+ integralSMC (
471
483
self .e_psi_int ,
472
484
e_psi , e_r ,
473
485
self .psi_d ,
474
486
self .r_d ,
475
487
self .a_d ,
476
- m ,
477
- d ,
478
- k ,
488
+ self .T_nomoto ,
489
+ self .K_nomoto ,
479
490
wn_d ,
480
491
zeta_d ,
481
- wn ,
482
- zeta ,
492
+ self .K_d ,
493
+ self .K_sigma ,
494
+ self .lam ,
495
+ self .phi_b ,
483
496
psi_ref ,
484
497
self .r_max ,
485
498
sampleTime
0 commit comments