当前位置:   article > 正文

(2-3-1)位置控制算法:无人机运动控制系统(1)

(2-3-1)位置控制算法:无人机运动控制系统(1)

2.3  无人机运动控制系统

本项目是一个基于Python的无人机运动控制算法库,提供了多个算法模块,包括基于鲁棒控制的Adaptive ISMC、经典的ISMC、线性系统的LQR等。该库通过模拟无人机的运动和姿态控制,在不同环境和故障条件下评估算法性能。同时,项目还包括了详细的文档和测试文件,方便用户理解和验证算法实现。本项目包含如下所示的功能模块:

  1. Copter Models:提供了无人机的非线性和线性动力学模型,用于模拟不同控制算法的性能。
  2. Control Algorithms:包括鲁棒控制算法Adaptive ISMC、经典的ISMC、线性系统的LQR等,用于实现无人机的运动和姿态控制。
  3. Fault Injection:具备故障注入功能,允许在模拟中引入不同类型的故障,评估算法对故障的鲁棒性。
  4. Simulation Environment:提供了模拟环境,支持在不同条件下评估算法性能,包括故障处理、控制分配等。
  5. Testing Infrastructure:包含详尽的测试文件和测试基础设施,确保算法的正确性和稳定性。

整体上,本项目旨在为用户提供一个全面的无人机运动控制算法库,支持算法开发、测试和验证。

实例2-8:无人机运动控制系统(源码路径:codes\2\locate\decmk-ftc-copter

2.3.1  Fym介绍

Fym是一个通用的Python动力学模拟器库,它最初是为需要高度准确积分(例如Runge-Kutta-Fehlberg方法或简单的rk45)以及一组相互交互的组件的飞行模拟器而开发的。对于积分,Fym支持各种Scipy积分方法,此外还有自己的固定步长求解器,如rk4。此外,Fym具有一种新颖的结构,提供系统每个组件的模块化设计,与Simulink非常相似。

库Fym最早被用于开发准确的飞行模拟器,航空航天工程师可以与OpenAI Gym一起使用以研究强化学习,这也是库名称为Fym(Flight + Gym)的原因。尽管现在它是一个通用的动力学模拟器,但许多代码和思想是在OpenAI Gym中设计的。本项目是基于库Fym实现的,在学习之前先通过如下命令进行安装:

pip install fym

2.3.2  控制算法

在本项目的“agents”目录中包含了4个Python程序文件,实现了对多旋翼无人机的不同控制算法,这些控制器旨在应对多旋翼无人机在不同工况下的位置和姿态控制问题,提高系统的鲁棒性和性能。

1. 被动失效(LoE)故障模型

文件decmk/agents/utils.py定义了一个名为LoE的类,代表了一种被动失效(LoE)故障模型。该类包含两个方法:get_effectiveness用于获取失效模型的效果,get用于应用失效模型到输入信号上。在测试代码中,创建了一个LoE对象,设置了失效时间、失效位置和失效水平,然后演示了获取失效效果和应用失效模型的过程。

  1. import numpy as np
  2. class LoE:
  3. def __init__(self, time=0, index=0, level=1.0):
  4. self.time = time
  5. self.index = index
  6. self.level = level
  7. def get(self, t, u):
  8. effectiveness = self.get_effectiveness(t, np.ones(u.shape[0]))
  9. return u * effectiveness.reshape(u.shape[0], 1)
  10. def get_effectiveness(self, t, effectiveness):
  11. if t >= self.time:
  12. effectiveness[self.index] = self.level
  13. return effectiveness
  14. if __name__ == "__main__":
  15. t = 4
  16. loe = LoE(time=3, index=0, level=0.5)
  17. print(loe.get_effectiveness(t, np.array([1, 2, 3, 4])))
  18. print(loe.get(t, np.array([1, 2, 3, 4])))

2. 基于线性和非线性的自适应容错滑模控制算法

文件decmk/agents/ISMC.py定义了两个类IntegralSMC_linear和IntegralSMC_nonlinear,分别实现了基于线性和非线性模型的自适应容错滑模控制算法方案。这些控制算法用于控制多旋翼无人机的位置移动,具备对执行器故障的适应性容错能力。其中包含位置跟踪的PD控制,滑模控制算法以及控制分配方案,以实现对飞行器的精确控制。文件decmk/agents/lqr.py的具体实现流程如下所示。

(1)定义了一个饱和函数sat,其功能是对输入变量s进行饱和处理,若s大于阈值eps,返回1;若s小于负阈值-eps,返回-1;否则返回s除以eps的结果。这样的函数通常用于限制变量在特定范围内波动。

  1. def sat(s, eps):
  2. if s > eps:
  3. return 1
  4. elif s < -eps:
  5. return -1
  6. else:
  7. return s/eps

(2)类IntegralSMC_linear 是基于自适应容错滑模控制方案的多旋翼无人机控制器,该类包含以下函数:

  1. __init__(self, J, m, g, d, ic, ref0):初始化函数,设置控制器的初始参数和状态。
  2. deriv(self, obs, ref):计算状态误差的导数,用于控制器设计。
  3. set_dot(self, obs, ref):设置状态误差的导数。
  4. get_FM(self, obs, ref, p, K, Kc, PHI, t):根据当前状态和参考状态计算控制力和滑模面,实现自适应容错滑模控制,返回控制力和滑模面。其中,参数obs表示当前状态,ref表示参考状态,p表示控制器参数,K表示PD控制器增益,Kc表示滑模面控制增益,PHI表示滑模面参数,t表示时间。
  1. class IntegralSMC_linear(BaseEnv):
  2. '''
  3. 参考文献
  4. Ban Wang, Youmin Zhang“一种自适应容错滑模控制分配方案用于多旋翼无人机受执行器故障影响”,IEEE工业电子学报,第65卷,第5期,2018年5月
  5. '''
  6. def __init__(self, J, m, g, d, ic, ref0):
  7. super().__init__()
  8. self.ic = ic
  9. self.ref0 = ref0
  10. self.J, self.m, self.g, self.d = J, m, g, d
  11. # x、y、z、roll、pitch、yaw的误差积分
  12. self.P = BaseSystem(np.vstack((self.ic[0] - self.ref0[0],
  13. self.ic[1] - self.ref0[0],
  14. self.ic[2] - self.ref0[2],
  15. self.ic[6] - self.ref0[6],
  16. self.ic[7] - self.ref0[7],
  17. self.ic[8] - self.ref0[8])))
  18. def deriv(self, obs, ref):
  19. # 观测
  20. obs = np.vstack((obs))
  21. x, y, z = obs[0:3]
  22. phi, theta, psi = obs[6:9]
  23. # 参考
  24. ref = np.vstack((ref))
  25. x_r, y_r, z_r = ref[0:3]
  26. phi_r, theta_r, psi_r = ref[6:9]
  27. dP = np.vstack((x - x_r,
  28. y - y_r,
  29. z - z_r,
  30. phi - phi_r,
  31. theta - theta_r,
  32. psi - psi_r))
  33. return dP
  34. def set_dot(self, obs, ref):
  35. dot = self.deriv(obs, ref)
  36. self.P.dot = dot
  37. def get_FM(self, obs, ref, p, K, Kc, PHI, t):
  38. p = np.vstack((p))
  39. px, py, pz, pphi, ptheta, ppsi = p
  40. K1, K2, K3, K4 = K
  41. k11, k12 = K1
  42. k21, k22 = K2
  43. k31, k32 = K3
  44. k41, k42 = K4
  45. kc1, kc2, kc3, kc4 = Kc
  46. PHI1, PHI2, PHI3, PHI4 = PHI
  47. # 模型
  48. J = self.J
  49. Ixx = J[0, 0]
  50. Iyy = J[1, 1]
  51. Izz = J[2, 2]
  52. m, g, d = self.m, self.g, self.d
  53. # 观测
  54. obs = np.vstack((obs))
  55. x, y, z, xd, yd, zd = obs[0:6]
  56. phi, theta, psi, phid, thetad, psid = obs[6:]
  57. # 参考
  58. ref = np.vstack((ref))
  59. x_r, y_r, z_r, xd_r, yd_r, zd_r = ref[0:6]
  60. phi_r, theta_r, psi_r, phid_r, thetad_r, psid_r = ref[6:]
  61. zdd_r = 0
  62. phidd_r = 0
  63. thetadd_r = 0
  64. psidd_r = 0
  65. # 初始条件
  66. z0, z0d = self.ic[2], self.ic[5]
  67. phi0, theta0, psi0, phi0d, theta0d, psi0d = self.ic[6:]
  68. z0_r, z0d_r = self.ref0[2], self.ref0[5]
  69. phi0_r, theta0_r, psi0_r, phi0d_r, theta0d_r, psi0d_r = self.ref0[6:]
  70. # 位置跟踪的PD控制(获取phi_ref、theta_ref)
  71. e_x = x - x_r
  72. e_xd = xd - xd_r
  73. e_y = y - y_r
  74. e_yd = yd - yd_r
  75. kp1, kd1, ki1 = np.array([0.5, 0.3, 0.2])
  76. kp2, kd2, ki2 = np.array([0.5, 0.3, 0.2])
  77. phi_r = -(kp1*e_y + kd1*e_yd + ki1*py)
  78. theta_r = kp2*e_x + kd2*e_xd + ki2*px
  79. # 误差定义
  80. e_z = z - z_r
  81. e_zd = zd - zd_r
  82. e_phi = phi - phi_r
  83. e_phid = phid - phid_r
  84. e_theta = theta - theta_r
  85. e_thetad = thetad - thetad_r
  86. e_psi = psi - psi_r
  87. e_psid = psid - psid_r
  88. # h**(-1)函数定义
  89. h1 = -m/cos(phi)/cos(theta)
  90. h2 = Ixx/d
  91. h3 = Iyy/d
  92. h4 = Izz
  93. # 滑模面
  94. s1 = e_zd + k12*e_z + k11*pz - k12*(z0-z0_r) - (z0d-z0d_r)
  95. s2 = e_phid + k22*e_phi + k21*pphi - k22*(phi0-phi0_r) - (phi0d-phi0d_r)
  96. s3 = e_thetad + k32*e_theta + k31*ptheta - k32*(theta0-theta0_r) - (theta0d-theta0d_r)
  97. s4 = e_psid + k42*e_psi + k41*ppsi - k42*(psi0-psi0_r) - (psi0d-psi0d_r)
  98. # 获取FM
  99. F = h1*(zdd_r - k12*e_zd - k11*e_z - g) - h1*kc1*sat(s1, PHI1)
  100. M1 = h2*(phidd_r - k22*e_phid - k21*e_phi - (Iyy-Izz)/Ixx*thetad*psid) \
  101. - h2*kc2*sat(s2, PHI2)
  102. M2 = h3*(thetadd_r - k32*e_thetad - k31*e_theta
  103. - (Izz-Ixx)/Iyy*phid*psid) - h3*kc3*sat(s3, PHI3)
  104. M3 = h4*(psidd_r - k42*e_psid - k41*e_psi - (Ixx-Iyy)/Izz*phid*thetad) \
  105. - h4*kc4*sat(s4, PHI4)
  106. action = np.vstack((F, M1, M2, M3))
  107. sliding = np.vstack((s1, s2, s3, s4))
  108. return action, sliding

(3)类IntegralSMC_nonlinear 是一个基于自适应容错滑模控制(Adaptive Fault-Tolerant Sliding Mode Control)方案的多旋翼无人机控制环境,该类实现了一个多旋翼无人机的自适应容错滑模控制器,通过对状态变量的控制力和力矩进行计算,实现对无人机运动的控制。类IntegralSMC_nonlinear 中的主要函数及其功能如下所示。

  1. __init__(self, J, m, g, d, ic, ref0):初始化函数,设置控制环境的初始条件和参考值。
  2. deriv(self, obs, ref):计算状态变量的导数,用于控制器的微分部分。
  3. set_dot(self, obs, ref):设置状态变量的导数,用于更新控制器的微分项。
  4. get_FM(self, obs, ref, p, t):根据当前状态、参考状态和控制参数,计算多旋翼无人机的控制力和力矩。其中,obs 是当前状态,ref 是参考状态,p 是控制参数,t 是时间。
  1. class IntegralSMC_nonlinear(BaseEnv):
  2. '''
  3. 参考文献
  4. Ban Wang, Youmin Zhang,“一种自适应容错滑模控制分配方案用于多旋翼无人机受执行器故障影响”,IEEE工业电子学报,第65卷,第5期,2018年5月
  5. '''
  6. def __init__(self, J, m, g, d, ic, ref0):
  7. super().__init__()
  8. self.ic_ = np.vstack((ic[0:6], np.vstack(quat2angle(ic[6:10])[::-1]), ic[10:]))
  9. self.ref0_ = np.vstack((ref0[0:6], np.vstack(quat2angle(ref0[6:10])[::-1]), ref0[10:]))
  10. self.J, self.m, self.g, self.d = J, m, g, d
  11. # x、y、z、roll、pitch、yaw的误差积分
  12. self.P = BaseSystem(np.vstack((self.ic_[0] - self.ref0_[0],
  13. self.ic_[1] - self.ref0_[1],
  14. self.ic_[2] - self.ref0_[2],
  15. self.ic_[6] - self.ref0_[6],
  16. self.ic_[7] - self.ref0_[7],
  17. self.ic_[8] - self.ref0_[8])))
  18. def deriv(self, obs, ref):
  19. # 观测
  20. obs = np.vstack((obs))
  21. obs_ = np.vstack((obs[0:6], np.vstack(quat2angle(obs[6:10])[::-1]), obs[10:]))
  22. x, y, z = obs_[0:3]
  23. phi, theta, psi = obs_[6:9]
  24. # 参考
  25. ref = np.vstack((ref))
  26. ref_ = np.vstack((ref[0:6], np.vstack(quat2angle(ref[6:10])[::-1]), ref[10:]))
  27. x_r, y_r, z_r = ref_[0:3]
  28. phi_r, theta_r, psi_r = ref_[6:9]
  29. dP = np.vstack((x - x_r,
  30. y - y_r,
  31. z - z_r,
  32. phi - phi_r,
  33. theta - theta_r,
  34. psi - psi_r))
  35. return dP
  36. def set_dot(self, obs, ref):
  37. dot = self.deriv(obs, ref)
  38. self.P.dot = dot
  39. def get_FM(self, obs, ref, p, t):
  40. K = np.array([[25, 15],
  41. [40, 20],
  42. [40, 20],
  43. [1, 1]])
  44. Kc = np.vstack((15, 15, 15, 10))
  45. PHI = np.vstack((0.8, 0.1, 0.1, 1))
  46. p = np.vstack((p))
  47. px, py, pz, pphi, ptheta, ppsi = p
  48. K1, K2, K3, K4 = K
  49. k11, k12 = K1
  50. k21, k22 = K2
  51. k31, k32 = K3
  52. k41, k42 = K4
  53. kc1, kc2, kc3, kc4 = Kc
  54. PHI1, PHI2, PHI3, PHI4 = PHI
  55. # 模型
  56. J = self.J
  57. Ixx = J[0, 0]
  58. Iyy = J[1, 1]
  59. Izz = J[2, 2]
  60. m, g, d = self.m, self.g, self.d
  61. # 观测
  62. obs = np.vstack((obs))
  63. obs_ = np.vstack((obs[0:6], np.vstack(quat2angle(obs[6:10])[::-1]), obs[10:]))
  64. x, y, z, xd, yd, zd = obs_[0:6]
  65. phi, theta, psi, phid, thetad, psid = obs_[6:]
  66. # 参考
  67. ref_ = np.vstack((ref[0:6], np.vstack(quat2angle(ref[6:10])[::-1]), ref[10:]))
  68. x_r, y_r, z_r, xd_r, yd_r, zd_r = ref_[0:6]
  69. phi_r, theta_r, psi_r, phid_r, thetad_r, psid_r = ref_[6:]
  70. zdd_r = 0
  71. phidd_r = 0
  72. thetadd_r = 0
  73. psidd_r = 0
  74. # 初始条件
  75. z0, z0d = self.ic_[2], self.ic_[5]
  76. phi0, theta0, psi0, phi0d, theta0d, psi0d = self.ic_[6:]
  77. z0_r, z0d_r = self.ref0_[2], self.ref0_[5]
  78. phi0_r, theta0_r, psi0_r, phi0d_r, theta0d_r, psi0d_r = self.ref0_[6:]
  79. # 位置跟踪的PD控制(获取phi_ref、theta_ref)
  80. e_x = x - x_r
  81. e_xd = xd - xd_r
  82. e_y = y - y_r
  83. e_yd = yd - yd_r
  84. kp1, kd1, ki1 = np.array([0.25, 0.11, 0.045])
  85. kp2, kd2, ki2 = np.array([0.25, 0.13, 0.03])
  86. phi_r = -(kp1*e_y + kd1*e_yd + ki1*py)
  87. theta_r = kp2*e_x + kd2*e_xd + ki2*px
  88. # 误差定义
  89. e_z = z - z_r
  90. e_zd = zd - zd_r
  91. e_phi = phi - phi_r
  92. e_phid = phid - phid_r
  93. e_theta = theta - theta_r
  94. e_thetad = thetad - thetad_r
  95. e_psi = psi - psi_r
  96. e_psid = psid - psid_r
  97. # h**(-1)函数定义
  98. h1 = -m/cos(phi)/cos(theta)
  99. h2 = Ixx/d
  100. h3 = Iyy/d
  101. h4 = Izz
  102. # 滑模面
  103. s1 = e_zd + k12*e_z + k11*pz - k12*(z0-z0_r) - (z0d-z0d_r)
  104. s2 = e_phid + k22*e_phi + k21*pphi - k22*(phi0-phi0_r) - (phi0d-phi0d_r)
  105. s3 = e_thetad + k32*e_theta + k31*ptheta - k32*(theta0-theta0_r) - (theta0d-theta0d_r)
  106. s4 = e_psid + k42*e_psi + k41*ppsi - k42*(psi0-psi0_r) - (psi0d-psi0d_r)
  107. # 获取FM
  108. F = h1*(zdd_r - k12*e_zd - k11*e_z - g) - h1*kc1*sat(s1, PHI1)
  109. M1 = h2*(phidd_r - k22*e_phid - k21*e_phi - (Iyy-Izz)/Ixx*thetad*psid) - h2*kc2*sat(s2, PHI2)
  110. M2 = h3*(thetadd_r - k32*e_thetad - k31*e_theta - (Izz-Ixx)/Iyy*phid*psid) - h3*kc3*sat(s3, PHI3)
  111. M3 = h4*(psidd_r - k42*e_psid - k41*e_psi - (Ixx-Iyy)/Izz*phid*thetad) - h4*kc4*sat(s4, PHI4)
  112. action = np.vstack((F, M1, M2, M3))
  113. return action

3. 最优控制算法

文件decmk/agents/lqr.py定义了一个线性二次型调节器(LQR)控制器和相应的控制类LQRController。LQR控制器通过计算系统状态和参考状态之间的差异,并应用调整力矩,实现对多旋翼无人机的姿态和位置控制。控制器中包括状态转换函数、初始化函数以及计算控制力和力矩的函数。LQR(线性二次型调节器)是最优控制中的一种经典算法。它基于状态空间模型,通过最小化状态与控制输入的二次代价函数来设计控制器,从而实现系统的最优控制。LQR在工程控制领域广泛应用,尤其在线性系统和近似线性系统的控制中表现出色。

  1. def LQR(A: np.array, B: np.array, Q: np.array, R: np.array, with_eigs=False) \
  2. -> np.array:
  3. P = lin.solve_continuous_are(A, B, Q, R)
  4. if np.size(R) == 1:
  5. K = (np.transpose(B).dot(P)) / R
  6. else:
  7. K = np.linalg.inv(R).dot((np.transpose(B).dot(P)))
  8. eig_vals, eig_vecs = np.linalg.eig(A - B.dot(K))
  9. if with_eigs:
  10. return K, P, eig_vals, eig_vecs
  11. else:
  12. return K, P
  13. class LQRController:
  14. def __init__(self, Jinv, m, g,
  15. Q=np.diag([1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0]),
  16. R=np.diag([1, 1, 1, 1]),
  17. ):
  18. self.Jinv = Jinv
  19. self.m, self.g = m, g
  20. self.trim_forces = np.vstack([self.m * self.g, 0, 0, 0])
  21. '''
  22. linearized condition near trim pt
  23. state variables with {pos, vel, Euler angle, omega}
  24. '''
  25. A = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
  26. [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
  27. [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
  28. [0, 0, 0, 0, 0, 0, 0, -g, 0, 0, 0, 0],
  29. [0, 0, 0, 0, 0, 0, g, 0, 0, 0, 0, 0],
  30. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  31. [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
  32. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
  33. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  34. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  35. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  36. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
  37. B = np.array([[0, 0, 0, 0],
  38. [0, 0, 0, 0],
  39. [0, 0, 0, 0],
  40. [0, 0, 0, 0],
  41. [0, 0, 0, 0],
  42. [-1/m, 0, 0, 0],
  43. [0, 0, 0, 0],
  44. [0, 0, 0, 0],
  45. [0, 0, 0, 0],
  46. [0, Jinv[0, 0], 0, 0],
  47. [0, 0, Jinv[1, 1], 0],
  48. [0, 0, 0, Jinv[2, 2]]])
  49. self.K, *_ = LQR(A, B, Q, R)
  50. def transform(self, y):
  51. # input comes in a form {pos, vel, quat, omega}
  52. if len(y) == 13:
  53. return np.vstack((y[0:6],
  54. np.vstack(quat2angle(y[6:10])[::-1]), y[10:]))
  55. def get_FM(self, obs, ref):
  56. x = self.transform(obs)
  57. x_ref = self.transform(ref)
  58. forces = -self.K.dot(x - x_ref) + self.trim_forces
  59. return forces

4. 自适应滑模控制(Adaptive Sliding Mode Control)算法

文件decmk/agents/AdaptiveISMC.py定义了两个多旋翼无人机控制器:AdaptiveISMC_linear 和 AdaptiveISMC_nonlinear。这些控制器基于自适应滑模控制(Adaptive Sliding Mode Control)实现,用于处理多旋翼无人机在存在故障情况下的姿态和位置控制。其中,AdaptiveISMC_linear采用线性模型,而AdaptiveISMC_nonlinear采用非线性模型。这些控制器通过引入滑动模式来实现鲁棒性,并通过自适应调节参数以适应系统变化。控制器的功能包括状态变量的微分方程、控制输入的计算以及反馈控制策略的实现。

文件decmk/agents/AdaptiveISMC.py的具体实现流程如下所示。

(1)类 AdaptiveISMC_linear 是一个多旋翼无人机控制器,基于自适应滑模控制方法,旨在处理多旋翼无人机在存在执行器故障的情况下的位置和姿态控制。该类包含了如下所示的功能函数:

  1. __init__(self, J, m, g, d, ic, ref0):类的初始化函数,设置控制器的初始参数和系统状态。
  2. deriv(self, obs, ref, sliding):计算多旋翼无人机系统的状态变量导数,用于模拟系统的动态行为。函数接受当前状态、参考状态和滑动表面作为输入,返回状态导数。
  3. set_dot(self, obs, ref, sliding):根据 deriv 函数计算的状态导数,更新控制器内部的状态变量。
  4. get_FM(self, obs, ref, p, gamma, K, Kc, PHI, t):根据当前状态、参考状态以及控制器的参数和状态,计算多旋翼无人机的控制输入和滑动表面。返回计算得到的控制输入和滑动表面。
  1. class AdaptiveISMC_linear(BaseEnv):
  2. def __init__(self, J, m, g, d, ic, ref0):
  3. super().__init__()
  4. self.ic = ic
  5. self.ref0 = ref0
  6. self.J, self.m, self.g, self.d = J, m, g, d
  7. # error integral of x, y, z, roll, pitch, yaw
  8. self.P = BaseSystem(np.vstack((self.ic[0] - self.ref0[0],
  9. self.ic[1] - self.ref0[1],
  10. self.ic[2] - self.ref0[2],
  11. self.ic[6] - self.ref0[6],
  12. self.ic[7] - self.ref0[7],
  13. self.ic[8] - self.ref0[8])))
  14. # parameter update, estimation
  15. self.gamma = BaseSystem(np.vstack((-m/cos(ic[6])/cos(ic[7]),
  16. J[0, 0]/d,
  17. J[1, 1]/d,
  18. J[2, 2])))
  19. def deriv(self, obs, ref, sliding):
  20. J, m, g = self.J, self.m, self.g
  21. Ixx = J[0, 0]
  22. Iyy = J[1, 1]
  23. Izz = J[2, 2]
  24. K = self.K
  25. Kc = self.Kc
  26. PHI = self.PHI
  27. K1, K2, K3, K4 = K
  28. k11, k12 = K1
  29. k21, k22 = K2
  30. k31, k32 = K3
  31. k41, k42 = K4
  32. kc1, kc2, kc3, kc4 = Kc
  33. PHI1, PHI2, PHI3, PHI4 = PHI
  34. # observation
  35. obs = np.vstack((obs))
  36. x, y, z = obs[0:3]
  37. zd = obs[5]
  38. phi, theta, psi, phid, thetad, psid = obs[6:]
  39. # reference
  40. ref = np.vstack((ref))
  41. x_r, y_r, z_r = ref[0:3]
  42. zd_r = ref[5]
  43. phi_r, theta_r, psi_r, phid_r, thetad_r, psid_r = ref[6:]
  44. # reference ddot term(z, phi, theta, psi)
  45. F_r = m*g
  46. M1_r = 0
  47. M2_r = 0
  48. M3_r = 0
  49. zdd_r = g - cos(phi_r)*cos(theta_r)*F_r/m
  50. phidd_r = (Iyy-Izz)/Ixx*thetad_r*psid_r + 1/Ixx*M1_r
  51. thetadd_r = (Izz-Ixx)/Iyy*phid_r*psid_r + 1/Iyy*M2_r
  52. psidd_r = (Ixx-Iyy)/Izz*phid_r*thetad_r + 1/Izz*M3_r
  53. # error
  54. e_x = x - x_r
  55. e_y = y - y_r
  56. e_z = z - z_r
  57. e_zd = zd - zd_r
  58. e_phi = phi - phi_r
  59. e_phid = phid - phid_r
  60. e_theta = theta - theta_r
  61. e_thetad = thetad - thetad_r
  62. e_psi = psi - psi_r
  63. e_psid = psid - psid_r
  64. # sliding surface
  65. s1, s2, s3, s4 = sliding
  66. # algebraic distance btw current state and boundary layer
  67. dels1 = s1 - PHI1*sat(s1, PHI1)
  68. dels2 = s2 - PHI2*sat(s2, PHI2)
  69. dels3 = s3 - PHI3*sat(s3, PHI3)
  70. dels4 = s4 - PHI4*sat(s4, PHI4)
  71. # derivs
  72. dP = np.vstack((e_x, e_y, e_z, e_phi, e_theta, e_psi))
  73. dgamma1 = -(- zdd_r + k12*e_zd + k11*e_z + g + kc1*sat(s1, PHI1))*dels1
  74. # dgamma1 should have negative sign to make Lyapunov like func > 0
  75. dgamma2 = (- phidd_r + k22*e_phid + k21*e_phi
  76. + (Iyy-Izz)/Ixx*thetad_r*psid_r + kc2*sat(s2, PHI2))*dels2
  77. dgamma3 = (- thetadd_r + k32*e_thetad + k31*e_theta
  78. + (Izz-Ixx)/Iyy*phid_r*psid_r + kc3*sat(s3, PHI3))*dels3
  79. dgamma4 = (- psidd_r + k42*e_psid + k41*e_psi
  80. + (Ixx-Iyy)/Izz*phid_r*thetad_r + kc4*sat(s4, PHI4))*dels4
  81. dgamma = np.vstack((dgamma1, dgamma2, dgamma3, dgamma4))
  82. return dP, dgamma
  83. def set_dot(self, obs, ref, sliding):
  84. dots = self.deriv(obs, ref, sliding)
  85. self.P.dot, self.gamma.dot = dots
  86. def get_FM(self, obs, ref, p, gamma, K, Kc, PHI, t):
  87. self.K = K
  88. self.Kc = Kc
  89. self.PHI = PHI
  90. p = np.vstack((p))
  91. px, py, pz, pphi, ptheta, ppsi = p
  92. gamma = np.vstack((gamma))
  93. gamma1, gamma2, gamma3, gamma4 = gamma
  94. K1, K2, K3, K4 = K
  95. k11, k12 = K1
  96. k21, k22 = K2
  97. k31, k32 = K3
  98. k41, k42 = K4
  99. kc1, kc2, kc3, kc4 = Kc
  100. PHI1, PHI2, PHI3, PHI4 = PHI
  101. # model
  102. J, g, m = self.J, self.g, self.m
  103. Ixx = J[0, 0]
  104. Iyy = J[1, 1]
  105. Izz = J[2, 2]
  106. # observation
  107. obs = np.vstack((obs))
  108. x, y, z, xd, yd, zd = obs[0:6]
  109. phi, theta, psi, phid, thetad, psid = obs[6:]
  110. # reference
  111. x_r, y_r, z_r, xd_r, yd_r, zd_r = ref[0:6]
  112. phi_r, theta_r, psi_r, phid_r, thetad_r, psid_r = ref[6:]
  113. # reference ddot term(z, phi, theta, psi)
  114. F_r = m*g
  115. M1_r = 0
  116. M2_r = 0
  117. M3_r = 0
  118. zdd_r = g - cos(phi_r)*cos(theta_r)*F_r/m
  119. phidd_r = (Iyy-Izz)/Ixx*thetad_r*psid_r + 1/Ixx*M1_r
  120. thetadd_r = (Izz-Ixx)/Iyy*phid_r*psid_r + 1/Iyy*M2_r
  121. psidd_r = (Ixx-Iyy)/Izz*phid_r*thetad_r + 1/Izz*M3_r
  122. # initial condition
  123. z0, z0d = self.ic[2], self.ic[5]
  124. phi0, theta0, psi0, phi0d, theta0d, psi0d = self.ic[6:]
  125. z0_r, z0d_r = self.ref0[2], self.ref0[5]
  126. phi0_r, theta0_r, psi0_r, phi0d_r, theta0d_r, psi0d_r = self.ref0[6:]
  127. # PD control for position tracking (get phi_ref, theta_ref)
  128. e_x = x - x_r
  129. e_xd = xd - xd_r
  130. e_y = y - y_r
  131. e_yd = yd - yd_r
  132. kp1, kd1, ki1 = np.array([0.3, 0.2, 0.1])
  133. kp2, kd2, ki2 = np.array([0.3, 0.2, 0.1])
  134. phi_r = -(kp1*e_y + kd1*e_yd + ki1*py)
  135. theta_r = kp2*e_x + kd2*e_xd + ki2*px
  136. # error definition
  137. e_z = z - z_r
  138. e_zd = zd - zd_r
  139. e_phi = phi - phi_r
  140. e_phid = phid - phid_r
  141. e_theta = theta - theta_r
  142. e_thetad = thetad - thetad_r
  143. e_psi = psi - psi_r
  144. e_psid = psid - psid_r
  145. # sliding surface
  146. s1 = e_zd + k12*e_z + k11*pz - k12*(z0-z0_r) - (z0d-z0d_r)
  147. s2 = e_phid + k22*e_phi + k21*pphi - k22*(phi0-phi0_r) - (phi0d-phi0d_r)
  148. s3 = e_thetad + k32*e_theta + k31*ptheta - k32*(theta0-theta0_r) \
  149. - (theta0d-theta0d_r)
  150. s4 = e_psid + k42*e_psi + k41*ppsi - k42*(psi0-psi0_r) - (psi0d-psi0d_r)
  151. # get FM
  152. F = gamma1*(zdd_r - k12*e_zd - k11*e_z - g) - gamma1*kc1*sat(s1, PHI1)
  153. M1 = gamma2*(phidd_r - k22*e_phid - k21*e_phi - (Iyy-Izz)/Ixx*thetad*psid) \
  154. - gamma2*kc2*sat(s2, PHI2)
  155. M2 = gamma3*(thetadd_r - k32*e_thetad - k31*e_theta - (Izz-Ixx)/Iyy*phid*psid) \
  156. - gamma3*kc3*sat(s3, PHI3)
  157. M3 = gamma4*(psidd_r - k42*e_psid - k41*e_psi - (Ixx-Iyy)/Izz*phid*thetad) \
  158. - gamma4*kc4*sat(s4, PHI4)
  159. action = np.vstack((F, M1, M2, M3))
  160. sliding = np.vstack((s1, s2, s3, s4))
  161. return action, sliding

(2)类 AdaptiveISMC_nonlinear 也是一个多旋翼无人机控制器,同样基于自适应滑模控制方法,专门设计用于处理多旋翼无人机在存在执行器故障的情况下的位置和姿态控制。在类 AdaptiveISMC_nonlinear包含如下所示的内置函数。

  1. __init__(self, J, m, g, d, ic, ref0):类的初始化函数,设置控制器的初始参数和系统状态。
  2. deriv(self, obs, ref, sliding):计算多旋翼无人机系统的状态变量导数,用于模拟系统的动态行为。函数接受当前状态、参考状态和滑动表面作为输入,返回状态导数。
  3. set_dot(self, obs, ref, sliding):根据 deriv 函数计算的状态导数,更新控制器内部的状态变量。特别地,在这个类中,还包括对控制器状态的一些修正。
  4. get_FM(self, obs, ref, p, gamma, t):根据当前状态、参考状态以及控制器的参数和状态,计算多旋翼无人机的控制输入和滑动表面。返回计算得到的控制输入和滑动表面。
  1. class AdaptiveISMC_nonlinear(BaseEnv):
  2. def __init__(self, J, m, g, d, ic, ref0):
  3. super().__init__()
  4. self.ic_ = np.vstack((ic[0:6],
  5. np.vstack(quat2angle(ic[6:10])[::-1]),
  6. ic[10:]))
  7. self.ref0_ = np.vstack((ref0[0:6],
  8. np.vstack(quat2angle(ref0[6:10])[::-1]),
  9. ref0[10:]))
  10. self.J, self.m, self.g, self.d = J, m, g, d
  11. # error integral of x, y, z, roll, pitch, yaw
  12. self.P = BaseSystem(np.vstack((self.ic_[0] - self.ref0_[0],
  13. self.ic_[1] - self.ref0_[1],
  14. self.ic_[2] - self.ref0_[2],
  15. self.ic_[6] - self.ref0_[6],
  16. self.ic_[7] - self.ref0_[7],
  17. self.ic_[8] - self.ref0_[8])))
  18. # parameter update, estimation
  19. self.gamma = BaseSystem(np.vstack((-m/cos(self.ic_[6])/cos(self.ic_[7]),
  20. J[0, 0]/d,
  21. J[1, 1]/d,
  22. J[2, 2])))
  23. def deriv(self, obs, ref, sliding):
  24. J, m, g = self.J, self.m, self.g
  25. Ixx = J[0, 0]
  26. Iyy = J[1, 1]
  27. Izz = J[2, 2]
  28. K = self.K
  29. Kc = self.Kc
  30. PHI = self.PHI
  31. K1, K2, K3, K4 = K
  32. k11, k12 = K1
  33. k21, k22 = K2
  34. k31, k32 = K3
  35. k41, k42 = K4
  36. kc1, kc2, kc3, kc4 = Kc
  37. PHI1, PHI2, PHI3, PHI4 = PHI
  38. # observation
  39. obs = np.vstack((obs))
  40. obs_ = np.vstack((obs[0:6],
  41. np.vstack(quat2angle(obs[6:10])[::-1]),
  42. obs[10:]))
  43. x, y, z = obs_[0:3]
  44. zd = obs_[5]
  45. phi, theta, psi, phid, thetad, psid = obs_[6:]
  46. # reference
  47. ref = np.vstack((ref))
  48. ref_ = np.vstack((ref[0:6],
  49. np.vstack(quat2angle(ref[6:10])[::-1]),
  50. ref[10:]))
  51. x_r, y_r, z_r = ref_[0:3]
  52. zd_r = ref_[5]
  53. phi_r, theta_r, psi_r, phid_r, thetad_r, psid_r = ref_[6:]
  54. # reference ddot term(z, phi, theta, psi)
  55. F_r = m*g
  56. M1_r = 0
  57. M2_r = 0
  58. M3_r = 0
  59. zdd_r = g - cos(phi_r)*cos(theta_r)*F_r/m
  60. phidd_r = (Iyy-Izz)/Ixx*thetad_r*psid_r + 1/Ixx*M1_r
  61. thetadd_r = (Izz-Ixx)/Iyy*phid_r*psid_r + 1/Iyy*M2_r
  62. psidd_r = (Ixx-Iyy)/Izz*phid_r*thetad_r + 1/Izz*M3_r
  63. # error
  64. e_x = x - x_r
  65. e_y = y - y_r
  66. e_z = z - z_r
  67. e_zd = zd - zd_r
  68. e_phi = phi - phi_r
  69. e_phid = phid - phid_r
  70. e_theta = theta - theta_r
  71. e_thetad = thetad - thetad_r
  72. e_psi = psi - psi_r
  73. e_psid = psid - psid_r
  74. # sliding surface
  75. s1, s2, s3, s4 = sliding
  76. # algebraic distance btw current state and boundary layer
  77. dels1 = s1 - PHI1*sat(s1, PHI1)
  78. dels2 = s2 - PHI2*sat(s2, PHI2)
  79. dels3 = s3 - PHI3*sat(s3, PHI3)
  80. dels4 = s4 - PHI4*sat(s4, PHI4)
  81. # derivs
  82. dP = np.vstack((e_x, e_y, e_z, e_phi, e_theta, e_psi))
  83. dgamma1 = -(- zdd_r + k12*e_zd + k11*e_z + g + kc1*sat(s1, PHI1))*dels1
  84. # dgamma1 should have negative sign to make Lyapunov like func > 0
  85. dgamma2 = (- phidd_r + k22*e_phid + k21*e_phi
  86. + (Iyy-Izz)/Ixx*thetad_r*psid_r + kc2*sat(s2, PHI2))*dels2
  87. dgamma3 = (- thetadd_r + k32*e_thetad + k31*e_theta
  88. + (Izz-Ixx)/Iyy*phid_r*psid_r + kc3*sat(s3, PHI3))*dels3
  89. dgamma4 = (- psidd_r + k42*e_psid + k41*e_psi
  90. + (Ixx-Iyy)/Izz*phid_r*thetad_r + kc4*sat(s4, PHI4))*dels4
  91. dgamma = np.vstack((dgamma1, dgamma2, dgamma3, dgamma4))
  92. return dP, dgamma
  93. def set_dot(self, obs, ref, sliding):
  94. dots = self.deriv(obs, ref, sliding)
  95. self.P.dot, self.gamma.dot = dots
  96. if self.gamma.state[0] > 0:
  97. self.gamma.state[0] = 0
  98. for i in range(3):
  99. if self.gamma.state[i+1] < 0:
  100. self.gamma.state[i+1] = 0
  101. def get_FM(self, obs, ref, p, gamma, t):
  102. K = np.array([[20, 15],
  103. [40, 20],
  104. [40, 20],
  105. [2, 1]])
  106. Kc = np.vstack((10, 10, 15, 5))
  107. PHI = np.vstack((0.8, 0.3, 0.3, 0.5))*0.1
  108. self.K = K
  109. self.Kc = Kc
  110. self.PHI = PHI
  111. p = np.vstack((p))
  112. px, py, pz, pphi, ptheta, ppsi = p
  113. gamma = np.vstack((gamma))
  114. gamma1, gamma2, gamma3, gamma4 = gamma
  115. K1, K2, K3, K4 = K
  116. k11, k12 = K1
  117. k21, k22 = K2
  118. k31, k32 = K3
  119. k41, k42 = K4
  120. kc1, kc2, kc3, kc4 = Kc
  121. PHI1, PHI2, PHI3, PHI4 = PHI
  122. # model
  123. J, g, m = self.J, self.g, self.m
  124. Ixx = J[0, 0]
  125. Iyy = J[1, 1]
  126. Izz = J[2, 2]
  127. # observation
  128. obs = np.vstack((obs))
  129. obs_ = np.vstack((obs[0:6],
  130. np.vstack(quat2angle(obs[6:10])[::-1]),
  131. obs[10:]))
  132. x, y, z, xd, yd, zd = obs_[0:6]
  133. phi, theta, psi, phid, thetad, psid = obs_[6:]
  134. # reference
  135. ref_ = np.vstack((ref[0:6],
  136. np.vstack(quat2angle(ref[6:10])[::-1]),
  137. ref[10:]))
  138. x_r, y_r, z_r, xd_r, yd_r, zd_r = ref_[0:6]
  139. phi_r, theta_r, psi_r, phid_r, thetad_r, psid_r = ref_[6:]
  140. # reference ddot term(z, phi, theta, psi)
  141. F_r = m*g
  142. M1_r = 0
  143. M2_r = 0
  144. M3_r = 0
  145. zdd_r = g - cos(phi_r)*cos(theta_r)*F_r/m
  146. phidd_r = (Iyy-Izz)/Ixx*thetad_r*psid_r + 1/Ixx*M1_r
  147. thetadd_r = (Izz-Ixx)/Iyy*phid_r*psid_r + 1/Iyy*M2_r
  148. psidd_r = (Ixx-Iyy)/Izz*phid_r*thetad_r + 1/Izz*M3_r
  149. # initial condition
  150. z0, z0d = self.ic_[2], self.ic_[5]
  151. phi0, theta0, psi0, phi0d, theta0d, psi0d = self.ic_[6:]
  152. z0_r, z0d_r = self.ref0_[2], self.ref0_[5]
  153. phi0_r, theta0_r, psi0_r, phi0d_r, theta0d_r, psi0d_r = self.ref0_[6:]
  154. # PD control for position tracking (get phi_ref, theta_ref)
  155. e_x = x - x_r
  156. e_xd = xd - xd_r
  157. e_y = y - y_r
  158. e_yd = yd - yd_r
  159. kp1, kd1, ki1 = np.array([0.25, 0.11, 0.045])*0.05
  160. kp2, kd2, ki2 = np.array([0.25, 0.13, 0.03])*0.05
  161. phi_r = -(kp1*e_y + kd1*e_yd + ki1*py)
  162. theta_r = kp2*e_x + kd2*e_xd + ki2*px
  163. # error definition
  164. e_z = z - z_r
  165. e_zd = zd - zd_r
  166. e_phi = phi - phi_r
  167. e_phid = phid - phid_r
  168. e_theta = theta - theta_r
  169. e_thetad = thetad - thetad_r
  170. e_psi = psi - psi_r
  171. e_psid = psid - psid_r
  172. # sliding surface
  173. s1 = e_zd + k12*e_z + k11*pz - k12*(z0-z0_r) - (z0d-z0d_r)
  174. s2 = e_phid + k22*e_phi + k21*pphi - k22*(phi0-phi0_r) - (phi0d-phi0d_r)
  175. s3 = e_thetad + k32*e_theta + k31*ptheta - k32*(theta0-theta0_r) \
  176. - (theta0d-theta0d_r)
  177. s4 = e_psid + k42*e_psi + k41*ppsi - k42*(psi0-psi0_r) - (psi0d-psi0d_r)
  178. # get FM
  179. F = gamma1*(zdd_r - k12*e_zd - k11*e_z - g) - gamma1*kc1*sat(s1, PHI1)
  180. M1 = gamma2*(phidd_r - k22*e_phid - k21*e_phi - (Iyy-Izz)/Ixx*thetad*psid) \
  181. - gamma2*kc2*sat(s2, PHI2)
  182. M2 = gamma3*(thetadd_r - k32*e_thetad - k31*e_theta - (Izz-Ixx)/Iyy*phid*psid) \
  183. - gamma3*kc3*sat(s3, PHI3)
  184. M3 = gamma4*(psidd_r - k42*e_psid - k41*e_psi - (Ixx-Iyy)/Izz*phid*thetad) \
  185. - gamma4*kc4*sat(s4, PHI4)
  186. action = np.vstack((F, M1, M2, M3))
  187. sliding = np.vstack((s1, s2, s3, s4))
  188. return action, sliding

总体而言,类AdaptiveISMC_nonlinear同样实现了自适应滑模控制算法,用于解决多旋翼无人机在执行器故障情况下的控制问题。相较于类AdaptiveISMC_linear,类AdaptiveISMC_nonlinear包含了更加复杂的动力学模型和更多的修正措施,以适应非线性的系统特性。

未完待续

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号