四旋翼无人机动力学与控制(1)-动力学模型


笔者近来开始接触四旋翼无人机,学习过程中写了一份有关无人机动力学与控制的python代码,在此做一些记录和原理解释。

附上仓库地址:四旋翼无人机仿真建模: 本仓库实现了四旋翼无人机的动力学仿真建模,并在此基础上完成了控制器的设计,包括串级PID、LQR、MPC等,实现了位置跟踪和路径规划。

总体框架与思路如图所示,四旋翼无人机的运动模型可以简单的看作是十二个状态变量(位置、速度、角度、角速度各三个变量)随运动而发生改变的过程,运动学方程如下图右半部分所示。

从框架讲起,作为一名飞行器控制专业的学生,四旋翼无人机在我眼中并不算是严格意义上的飞行器,我对其的理解更偏向于robotic,与固定翼相比,四旋翼的动力学模型更简单,我浅显的理解为依靠四个轴上的电机带动螺旋桨提供升力,通过调节电机转速制造升力差引起角度的偏转进而带动无人机运动,因此就引出了四旋翼无人机常见的分级控制策略,分为角速度、姿态、速度和位置由内到外的四个环,详细内容将在下一篇文章展开。

笔者构建的动力学模型分为上图的几个部分,无人机构型为x型,定义电机顺序如上图左上所示,电机作为执行器,近似看作一个一阶延迟环节,控制分配器由升力和力矩在四轴上的分解和合成计算得出。

选取四阶龙格库塔法进行状态更新,由此可以开始编写程序了:

common_function:

  1. # Author:gyx
  2. # Usage: common function
  3. # Last change: 2024-7-20
  4. import numpy as np
  5. def dcm_from_euler(euler_angles):
  6. """
  7. 计算方向余弦矩阵(DCM)(Earth2Body)
  8. :param roll: 滚转角,单位为弧度
  9. :param pitch: 俯仰角,单位为弧度
  10. :param yaw: 偏航角,单位为弧度
  11. :return: 方向余弦矩阵(DCM)
  12. """
  13. roll, pitch, yaw = euler_angles
  14. c_roll = np.cos(roll)
  15. s_roll = np.sin(roll)
  16. c_pitch = np.cos(pitch)
  17. s_pitch = np.sin(pitch)
  18. c_yaw = np.cos(yaw)
  19. s_yaw = np.sin(yaw)
  20. # 构建方向余弦矩阵
  21. dcm = np.array([
  22. [c_yaw * c_pitch, c_yaw * s_pitch * s_roll - s_yaw * c_roll, c_yaw * s_pitch * c_roll + s_yaw * s_roll],
  23. [s_yaw * c_pitch, s_yaw * s_pitch * s_roll + c_yaw * c_roll, s_yaw * s_pitch * c_roll - c_yaw * s_roll],
  24. [-s_pitch, c_pitch * s_roll, c_pitch * c_roll]
  25. ])
  26. return dcm
  27. def rotation_matrix(euler_angles): # (Body2Earth)
  28. phi, theta, psi = euler_angles
  29. R_x = np.array([[1, 0, 0],
  30. [0, np.cos(phi), -np.sin(phi)],
  31. [0, np.sin(phi), np.cos(phi)]])
  32. R_y = np.array([[np.cos(theta), 0, np.sin(theta)],
  33. [0, 1, 0],
  34. [-np.sin(theta), 0, np.cos(theta)]])
  35. R_z = np.array([[np.cos(psi), -np.sin(psi), 0],
  36. [np.sin(psi), np.cos(psi), 0],
  37. [0, 0, 1]])
  38. return R_z @ R_y @ R_x
  39. def angle_body2world(euler_angles):
  40. phi, theta, psi = euler_angles
  41. Trans_matrix = np.array([[1, np.tan(theta) * np.sin(phi), np.tan(theta) * np.cos(phi)],
  42. [0, np.cos(phi), -np.sin(phi)],
  43. [0, np.sin(phi) / np.cos(theta), np.cos(phi) / np.cos(theta)]])
  44. return Trans_matrix
  45. def rk4_step(f, state, u, t, dt):
  46. k1 = f(state, u, t)
  47. print([x * 0.5 * dt for x in k1])
  48. k2 = f(state + [x * 0.5 * dt for x in k1], u, t + 0.5 * dt)
  49. k3 = f(state + [x * 0.5 * dt for x in k2], u, t + 0.5 * dt)
  50. k4 = f(state + [x * dt for x in k3], u, t + dt)
  51. return state + (dt / 6) * (k1 + 2 * k2 + 2 * k3 + k4)

dynamic:

  1. # Author:gyx
  2. # Usage: build uav dynamics model
  3. # Last change: 2024-7-20
  4. import numpy as np
  5. from common_function import dcm_from_euler, rotation_matrix
  6. class UAVDynamics:
  7. def __init__(self, params):
  8. self.params = params
  9. self.w_current = params.ModelInit_Rads
  10. def get_angular_velocity_derivative(self, M, J, omega):
  11. return np.linalg.inv(J) @ (M - np.cross(omega, J @ omega))
  12. def get_linear_velocity_derivative(self, F, m):
  13. return np.clip(F / m, -0.4, 0.4)
  14. def Obtain_force_torque(self, w, R, Cm, Ct, Vb, Cd, wb, Cdm, Jrp):
  15. M_rctcm = np.array([
  16. [-np.sin(np.pi / 4) * R * Ct, np.sin(np.pi / 4) * R * Ct, np.sin(np.pi / 4) * R * Ct,
  17. -np.sin(np.pi / 4) * R * Ct], # Roll torque
  18. [np.sin(np.pi / 4) * R * Ct, -np.sin(np.pi / 4) * R * Ct, np.sin(np.pi / 4) * R * Ct,
  19. -np.sin(np.pi / 4) * R * Ct], # Pitch torque
  20. [Cm, Cm, -Cm, -Cm] # Yaw torque
  21. ])
  22. Mp = np.dot(M_rctcm, w ** 2) # Torque
  23. Fp = np.array([0, 0, -np.sum(Ct * (w ** 2))]) # Thrust
  24. Fd = -Cd * Vb * np.abs(Vb) * 0.5 # Aerodynamic force
  25. Md = -Cdm * wb * np.abs(wb) # Aerodynamic moment
  26. # Gyro moment
  27. Ga = np.zeros(3)
  28. Ga[0] = Jrp * wb[1] * (w[0] + w[1] - w[2] - w[3])
  29. Ga[1] = Jrp * wb[0] * (-w[0] - w[1] + w[2] + w[3])
  30. return Fp, Fd, Mp, Md, Ga
  31. def motor_dynamics(self, w_current, w_target, T, dt):
  32. dw = (w_target - w_current) / T
  33. return w_current + dw * dt
  34. def state_derivative(self, state, w_target,dt):
  35. velB, angEuler, rateB = state
  36. m = self.params.ModelParam_uavMass
  37. J = self.params.ModelParam_uavJ
  38. g = self.params.ModelParam_envGravityAcc
  39. uavType = self.params.ModelParam_uavType
  40. R = self.params.ModelParam_uavR
  41. Cm = self.params.ModelParam_rotorCm
  42. Ct = self.params.ModelParam_rotorCt
  43. Cd = self.params.ModelParam_uavCd
  44. Cdm = self.params.ModelParam_uavCCm
  45. Jrp = self.params.ModelParam_motorJm
  46. T = self.params.ModelParam_motorT
  47. self.w_current = self.motor_dynamics(self.w_current, w_target, T, dt)
  48. Fp, Fd, Mp, Md, Ga = self.Obtain_force_torque(self.w_current, R, Cm, Ct, velB, Cd, rateB, Cdm, Jrp)
  49. dcm = dcm_from_euler(angEuler)
  50. total_force = Fp + Fd + np.array([0, 0, m * g]).dot(dcm)
  51. total_torque = Mp + Md + Ga
  52. velB_dot = self.get_linear_velocity_derivative(total_force, m)
  53. rateB_dot = self.get_angular_velocity_derivative(total_torque, J, rateB)
  54. return velB_dot, rateB_dot
  55. def update_dynamics(self, state, w_target, dt):
  56. velB, angEuler, rateB = state
  57. # Runge-Kutta 4th Order Method
  58. k1_velB_dot, k1_rateB_dot = self.state_derivative(state, w_target,dt)
  59. k2_velB_dot, k2_rateB_dot = self.state_derivative(
  60. (velB + 0.5 * k1_velB_dot * dt, angEuler, rateB + 0.5 * k1_rateB_dot * dt), w_target,dt)
  61. k3_velB_dot, k3_rateB_dot = self.state_derivative(
  62. (velB + 0.5 * k2_velB_dot * dt, angEuler, rateB + 0.5 * k2_rateB_dot * dt), w_target,dt)
  63. k4_velB_dot, k4_rateB_dot = self.state_derivative(
  64. (velB + k3_velB_dot * dt, angEuler, rateB + k3_rateB_dot * dt), w_target,dt)
  65. velB = velB + (k1_velB_dot + 2 * k2_velB_dot + 2 * k3_velB_dot + k4_velB_dot) * dt / 6
  66. rateB = rateB + (k1_rateB_dot + 2 * k2_rateB_dot + 2 * k3_rateB_dot + k4_rateB_dot) * dt / 6
  67. return velB, angEuler, rateB

            </div><div data-report-view="{&quot;mod&quot;:&quot;1585297308_001&quot;,&quot;spm&quot;:&quot;1001.2101.3001.6548&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/perfectdisaster/article/details/143431038&quot;,&quot;extend1&quot;:&quot;pc&quot;,&quot;ab&quot;:&quot;new&quot;}"><div></div></div>
    </div>

文章作者: 郭昱鑫
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 郭昱鑫 !
  目录