继上一篇博客搭建完无人机的动力学模型之后,进而可以开始设计控制算法,首先需要了解常见的飞控策略:
还是先附上仓库地址:四旋翼无人机仿真建模: 本仓库实现了四旋翼无人机的动力学仿真建模,并在此基础上完成了控制器的设计,包括串级PID、LQR、MPC等,实现了位置跟踪和路径规划。
总体框架如上图,本项目采用常见的分级控制,由内到外分为角速率环、姿态环、速度环和位置环。上一篇中笔者写过,我将无人机的运动浅显的理解为依靠四个轴上的电机带动螺旋桨提供升力,通过调节电机转速制造升力差引起角度的偏转进而带动其运动,因此无人机的角度偏转是无人机在xy平面内运动的前提。换句话说,控制好角度是控制好位置的前提,而采用角速率环和速度环是由于被控量(位置、姿态)和控制量(加速度、角加速度)之间差了两个阶次,只使用一个环无法控制中间变量,容易导致超调,因此加入一个中间环来达到更好的控制效果。
本项目中采用了PID、LQR和MPC三种控制算法,以下是控制部分的代码:
(1)PID:原理不做阐述
- # Author:gyx
- # Usage: pid controller
- # Last change: 2024-7-20
-
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- class PIDController:
- def __init__(self, Kp, Ki, Kd, integrator_max=None, integrator_min=None,max=None,min=None):
- self.Kp = Kp
- self.Ki = Ki
- self.Kd = Kd
- self.integrator = 0
- self.prev_error = 0
- self.integrator_max = integrator_max
- self.integrator_min = integrator_min
- self.max = max
- self.min = min
- self.error = 0
- self.measurement_history = []
- self.setpoint_history = []
-
- def reset(self):
- self.integrator = 0
- self.prev_error = 0
-
- def update(self, setpoint, measurement, dt):
- self.measurement_history.append(measurement)
- self.setpoint_history.append(setpoint)
- error = setpoint - measurement
- self.error = error
- self.integrator += error * dt
- if self.integrator_max is not None and self.integrator > self.integrator_max:
- self.integrator = self.integrator_max
- if self.integrator_min is not None and self.integrator < self.integrator_min:
- self.integrator = self.integrator_min
-
- derivative = (error - self.prev_error) / dt
- output = self.Kp * error + self.Ki * self.integrator + self.Kd * derivative
- self.prev_error = error
- if self.max is not None and self.min is not None:
- output = np.clip(output,self.min,self.max)
- return output
-
- def plot_error(self,fig,i,title='none'):
- # plt.plot(self.setpoint_history, [i for i in self.setpoint_history], linewidth =2.0, label = r"setpoint",color='b', linestyle='dotted')
- # plt.plot(self.measurement_history, [i for i in self.measurement_history], linewidth =2.0, label = r"setpoint",color='r',linestyle='dashed')
- ax = fig.add_subplot(131 + i)
- ax.plot([i/100 for i in range(len(self.setpoint_history))], self.setpoint_history, label='setpoint')
- ax.plot([i/100 for i in range(len(self.measurement_history))], self.measurement_history,label='measurement')
- ax.set_xlabel('time')
- ax.set_ylabel('value')
- ax.set_title(title)
- ax.legend()
-
-
- class CascadePIDController:
- def __init__(self, outer_controller, inner_controller):
- self.outer_controller = outer_controller
- self.inner_controller = inner_controller
-
- def update(self, outer_setpoint, outer_measurement, inner_measurement, dt):
- outer_output = self.outer_controller.update(outer_setpoint, outer_measurement, dt)
- inner_output = self.inner_controller.update(outer_output, inner_measurement, dt)
- return inner_output
-
-
- class posion_pos_controller:
- def __init__(self,params):
- self.params = params
-
- def position_controller(self):
- x_position_controller = PIDController(self.params.Kpxp, 0, 0, integrator_max=1,
- integrator_min=-1, max=5, min=-5)
- x_velocity_controller = PIDController(self.params.Kvxp, self.params.Kvxi, self.params.Kvxd, integrator_max=1,
- integrator_min=-1)
- y_position_controller = PIDController(self.params.Kpyp, 0, 0, integrator_max=1,
- integrator_min=-1, max=5, min=-5, )
- y_velocity_controller = PIDController(self.params.Kvyp, self.params.Kvyi, self.params.Kvyd, integrator_max=1,
- integrator_min=-1)
-
- height_position_controller = PIDController(self.params.Kpzp, 0, 0, integrator_max=1,
- integrator_min=-1, min=-3, max=3)
- height_velocity_controller = PIDController(self.params.Kvzp, self.params.Kvzi, self.params.Kvzd, integrator_max=1,
- integrator_min=-1, min=-0.4, max=0.4)
- x_controller = CascadePIDController(x_position_controller, x_velocity_controller)
- y_controller = CascadePIDController(y_position_controller, y_velocity_controller)
- height_controller = CascadePIDController(height_position_controller, height_velocity_controller)
- return [x_controller,y_controller,height_controller]
-
- def pos_controller(self):
- DEG2RAD = self.params.DEG2RAD
- roll_angle_controller = PIDController(self.params.Kp_RP_ANGLE, 0, 0, integrator_max=1,
- integrator_min=-1, max=DEG2RAD * 35, min=-DEG2RAD * 35)
- roll_rate_controller = PIDController(self.params.Kp_RP_AngleRate, self.params.Ki_RP_AngleRate,
- self.params.Kd_RP_AngleRate, integrator_max=1,
- integrator_min=-1, max=DEG2RAD * 220, min=-DEG2RAD * 220)
- roll_controller = CascadePIDController(roll_angle_controller, roll_rate_controller)
-
- pitch_angle_controller = PIDController(self.params.Kp_RP_ANGLE, 0, 0, integrator_max=1,
- integrator_min=-1, max=DEG2RAD * 35, min=-DEG2RAD * 35)
- pitch_rate_controller = PIDController(self.params.Kp_RP_AngleRate, self.params.Ki_RP_AngleRate,
- self.params.Kd_RP_AngleRate, integrator_max=1,
- integrator_min=-1, max=DEG2RAD * 220, min=-DEG2RAD * 220)
- pitch_controller = CascadePIDController(pitch_angle_controller, pitch_rate_controller)
- yaw_angle_controller = PIDController(self.params.Kp_RP_ANGLE, 0, 0, integrator_max=1,
- integrator_min=-1, max=DEG2RAD * 35, min=-DEG2RAD * 35)
- yaw_rate_controller = PIDController(self.params.Kp_YAW_AngleRate, self.params.Ki_YAW_AngleRate,
- self.params.Kd_YAW_AngleRate, integrator_max=1,
- integrator_min=-1, max=DEG2RAD * 220, min=-DEG2RAD * 220)
- yaw_controller = CascadePIDController(yaw_angle_controller, yaw_rate_controller)
- return [roll_controller,pitch_controller,yaw_controller]
(2)LQR:
- # Author:gyx
- # Usage: LQR controller
- # Last change: 2024-7-20
-
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- class LQRController:
- def __init__(self, A, B, Q, R):
- self.A = A
- self.B = B
- self.Q = Q
- self.R = R
- self.measurement_history = []
- self.setpoint_history = []
-
- def lqr_solve(self):
- n = self.A.shape[0]
- m = self.B.shape[1]
- # Riccati equation using a Lyapunov approach
- Z = np.vstack([
- np.hstack([self.A, -self.B @ np.linalg.inv(self.R) @ self.B.T]),
- np.hstack([-self.Q, -self.A.T])
- ])
- eigvals, eigvecs = np.linalg.eig(Z)
- # Select stable eigenvalues
- stable_indices = np.where(np.real(eigvals) < 0)[0]
- eigvecs_stable = eigvecs[:, stable_indices]
-
- X = eigvecs_stable[:n, :]
- Y = eigvecs_stable[n:, :]
- # Solve P
- P = np.real(Y @ np.linalg.inv(X))
- # Compute gain
- K = np.linalg.inv(self.R) @ self.B.T @ P
-
- eigVals, _ = np.linalg.eig(self.A - self.B @ K)
-
- return K, P, eigVals
-
- def update(self, setpoint, measurement):
- self.measurement_history.append(measurement)
- self.setpoint_history.append(setpoint)
- K, _, _ = self.lqr_solve()
- u = -K @ (measurement - setpoint)
- return u
-
- def plot_error(self, title='none'):
- self.setpoint_history = np.array(self.setpoint_history)
- self.measurement_history = np.array(self.measurement_history)
- fig = plt.figure(figsize=(14, 4))
- subtitle=['x','y','z']
- for i in range(len(self.setpoint_history[0])):
- ax = fig.add_subplot(131+i)
- ax.plot([i / 100 for i in range(len(self.setpoint_history[:,i]))], self.setpoint_history[:,i], label='setpoint')
- ax.plot([i / 100 for i in range(len(self.measurement_history[:,i]))], self.measurement_history[:,i], label='measurement')
- ax.set_xlabel('time')
- ax.set_ylabel('value')
- ax.set_title(subtitle[i]+title)
- ax.legend()
- plt.tight_layout()
- # fig.legend()
-
-
-
- if __name__ == '__main__':
- A = np.array([[0., 1.], [-1., -1.]])
- B = np.array([[0.], [1.]])
- Q = np.array([[1., 0.], [0., 1.]])
- R = np.array([[1.]])
-
- controller = LQRController(A, B, Q, R)
- K, P, eigVals = controller.lqr_solve()
- x = np.array([0, 0])
- r = np.array([1, 0])
- u = controller.update(np.array([1, 0]), np.array([0, 0]))
-
- print("LQR gain matrix K:")
- print(K)
- print("\nSolution to Riccati equation P:")
- print(P)
- print("\nClosed loop system eigenvalues:")
- print(eigVals)
- print("Control value:")
- print(u)
(3)MPC:
- # Author:gyx
- # Usage: MPC controller
- # Last change: 2024-7-20
-
- import numpy as np
- import matplotlib.pyplot as plt
-
- class MPCController:
- def __init__(self, A, B, C, N, Q, R, u_min, u_max, reg=1e-5):
- self.A = A
- self.B = B
- self.C = C
- self.N = N
- self.Q = Q
- self.R = R
- self.u_min = u_min
- self.u_max = u_max
- self.reg = reg # 正则化参数
- self.measurement_history = []
- self.setpoint_history = []
-
- def mpc_control(self, x, r):
- x = x.reshape(-1,1)
- r = r.reshape(-1,1)
- n_states = self.A.shape[0]
- n_controls = self.B.shape[1]
- # 构建优化问题
- H = np.zeros((self.N * n_controls, self.N * n_controls))
- F = np.zeros((self.N * n_controls, 1))
- for i in range(self.N):
- H[i * n_controls:(i + 1) * n_controls, i * n_controls:(i + 1) * n_controls] = self.R
- F[i * n_controls:(i + 1) * n_controls, 0] = 0
- G = np.zeros((self.N * n_states, self.N * n_controls))
- E = np.zeros((self.N * n_states, n_states))
- L = np.zeros((self.N * n_states, 1))
- for i in range(self.N):
- for j in range(i + 1):
- G[i * n_states:(i + 1) * n_states, j * n_controls:(j + 1) * n_controls] \
- = np.linalg.matrix_power(self.A,i - j) @ self.B
- E[i * n_states:(i + 1) * n_states, :] = np.linalg.matrix_power(self.A, i + 1)
- L[i * n_states:(i + 1) * n_states, :] = np.linalg.matrix_power(self.A, i + 1) @ x - r
-
- Q_bar = np.kron(np.eye(self.N), self.Q)
- H += G.T @ Q_bar @ G
- F += (G.T @ Q_bar @ L).reshape(-1, 1)
-
- # 计算最优控制输入
- u_opt = -np.linalg.inv(H) @ F
-
- # 取第一个控制输入
- u = u_opt[:n_controls]
-
- return u
-
- def update(self, setpoint, measurement):
- self.measurement_history.append(measurement)
- self.setpoint_history.append(setpoint)
- u = self.mpc_control(np.array(measurement), np.array(setpoint))
- # print(u)
- return u
-
- def plot_error(self, title='none'):
- self.setpoint_history = np.array(self.setpoint_history)
- self.measurement_history = np.array(self.measurement_history)
- subtitle = ['x', 'y', 'z']
- fig = plt.figure(figsize=(14, 4))
- for i in range(len(self.setpoint_history[0])):
- ax = fig.add_subplot(131+i)
- ax.plot([i / 100 for i in range(len(self.setpoint_history[:, i]))], self.setpoint_history[:, i],
- label='setpoint')
- ax.plot([i / 100 for i in range(len(self.measurement_history[:, i]))], self.measurement_history[:, i],
- label='measurement')
- ax.set_xlabel('time')
- ax.set_ylabel('value')
- ax.set_title(subtitle[i]+title)
- ax.legend()
- plt.tight_layout()
-
- if __name__ == '__main__':
- A = np.array([[1, 0,0], [0, 1,0],[0,0,1]])
- B = np.array([[0.5,0.6,0.2], [1,0.1,0.4],[0.5,0.5,0.8]])
- C = np.eye(3) # 输出矩阵
- Q = np.eye(3)*2
- R = np.eye(1)
- N = 10
- u_min = -1
- u_max = 1
- reg = 1e-5
-
- outer_controller = MPCController(A, B, C, N, Q, R, u_min, u_max, reg)
- inner_controller = MPCController(A, B, C, N, Q, R, u_min, u_max, reg)
- setpoint = np.array([[1], [1],[1]])
- # r = np.ones((1, N)) # 目标为1
- measurement = np.array([[0],[0],[0]])
- x = np.array([[0], [0],[0]])
- x_dot = np.array([[0], [0], [0]])
- for _ in range(10):
- u = outer_controller.update(setpoint, x)
- u_v = inner_controller.update(u,x_dot)
- x_dot = A @ x_dot + B @ u_v.reshape(-1, 1)
- x = A @ x + B @ x_dot.reshape(-1, 1)
- # x = A @ x + B @ u.reshape(-1, 1)
- y = C @ x
- print("控制输入 u:")
- print(u)
- print('状态 x:')
- print(x)
- inner_controller.plot_error()
- outer_controller.plot_error()
- plt.show()
仿真运行代码:
- import numpy as np
- import matplotlib.pyplot as plt
- from init_control import UAVParameters
- from uav_dynamics import UAVDynamics
- from common_function import rotation_matrix, angle_body2world
- from PIDController import posion_pos_controller
- from LQRController import LQRController
- from MPCController import MPCController
- from square_signal import generate_ramp_signal
-
- class UAVSimulation:
- def __init__(self, params, dynamics, position_controller, pose_controller, controller_type):
- self.params = params
- self.dynamics = dynamics
- self.controller_type = controller_type
- if controller_type == "PID":
- self.x_controller = position_controller[0]
- self.y_controller = position_controller[1]
- self.height_controller = position_controller[2]
- else:
- self.position_controller = position_controller[0]
- self.velocity_controller = position_controller[1]
- self.roll_controller = pose_controller[0]
- self.pitch_controller = pose_controller[1]
- self.yaw_controller = pose_controller[2]
- self.position_history = []
- self.setpoint_history = []
-
- def desired_euler_angles(self, eax, eay, psi):
- """
- Convert the desired horizontal acceleration to the desired Euler angle
- Input:
- eax, eay: desired horizontal acceleration
- Output:
- phi, theta: desired roll and pitch
- """
- g = 9.8 # 重力加速度 (m/s^2)
-
- phi = (-np.sin(psi) * eax + np.cos(psi) * eay) / g
- theta = (-np.cos(psi) * eax - np.sin(psi) * eay) / g
-
- return phi, theta
-
- def motor_mixer(self, roll, pitch, yaw, thrust):
- """
- Control allocation. The quadrotor type is X-configuration,
- and the airframe is as follows:
- 3↓ 1↑
- \ /
- / \
- 2↑ 4↓
- Input:
- roll, pitch, yaw: attitude controller output.
- thrust: total thrust.
- Output:
- M1, M2, M3, M4: motor speed commands.
- """
- idle_PWM = 1000
- scale = 1000
-
- M1 = (thrust - roll + pitch + yaw) * scale + idle_PWM
- M2 = (thrust + roll - pitch + yaw) * scale + idle_PWM
- M3 = (thrust + roll + pitch - yaw) * scale + idle_PWM
- M4 = (thrust - roll - pitch - yaw) * scale + idle_PWM
-
- return M1, M2, M3, M4
-
- def pwm_to_rpm(self, pwm):
- """
- Convert PWM signal to RPM. This is a simple linear approximation.
- Input:
- pwm: PWM signal value
- Output:
- rpm: motor speed in RPM
- """
- min_pwm = 1000
- max_pwm = 2000
-
- # 限制PWM范围
- pwm = np.clip(pwm, min_pwm, max_pwm)
-
- # 线性插值计算RPM
- rpm = np.clip((pwm - min_pwm) / (max_pwm - min_pwm), -1, 1)
- return rpm
-
- def run(self, square_corners, duration, dt):
- DEG2RAD = self.params.DEG2RAD
- posE = self.params.ModelInit_PosE.astype(np.float64)
- velB = self.params.ModelInit_VelB.astype(np.float64)
- velE = self.params.ModelInit_VelB.astype(np.float64)
- angEuler = self.params.ModelInit_AngEuler
- rateB = self.params.ModelInit_RateB
- rateE = self.params.ModelInit_RateB
- ModelParam_motorCr = self.params.ModelParam_motorCr
- ModelParam_motorWb = self.params.ModelParam_motorWb
-
- state = [velB, angEuler, rateB]
- current_corner_index = 0
- time_steps = int(duration / dt)
- num_steps = time_steps // (len(square_corners) - 1)
- # next_corner_time = time_steps // (len(square_corners)-1)
- input_signal = generate_ramp_signal(square_corners, num_steps)
-
- for step in range(time_steps):
- setpoint = input_signal[step]
- eax, eay, altitude_output = None, None, None
- print('setpoint:', setpoint)
- if self.controller_type == 'PID':
- eax = self.x_controller.update(outer_setpoint=setpoint[0], outer_measurement=posE[0],
- inner_measurement=velE[0], dt=dt)
- eay = self.y_controller.update(outer_setpoint=setpoint[1], outer_measurement=posE[1],
- inner_measurement=velE[1], dt=dt)
- altitude_output = self.height_controller.update(outer_setpoint=setpoint[2], outer_measurement=posE[2],
- inner_measurement=velE[2], dt=dt)
- else:
- vel_setpoint = self.position_controller.update(setpoint, posE)
- # 速度环LQR控制
- acc_setpoint = self.velocity_controller.update(vel_setpoint, velE)
- if self.controller_type == "MPC":
- eax, eay, altitude_output = acc_setpoint[0][0], acc_setpoint[1][0], acc_setpoint[2][0]
- elif self.controller_type == "LQR":
- eax, eay, altitude_output = acc_setpoint[0], acc_setpoint[1], acc_setpoint[2]
- else:
- print("unknown controller")
- phi, theta = self.desired_euler_angles(eax, eay, angEuler[2])
- phi = np.clip(phi, -35 * DEG2RAD, 35 * DEG2RAD)
- theta = np.clip(theta, -35 * DEG2RAD, 35 * DEG2RAD)
- print('eax,eay:', eax, eay)
- print('phi,theta:', phi, theta)
- roll_output = np.clip(self.roll_controller.update(outer_setpoint=phi, outer_measurement=angEuler[0],
- inner_measurement=rateE[0], dt=dt), -1, 1)
- pitch_output = np.clip(self.pitch_controller.update(outer_setpoint=theta, outer_measurement=angEuler[1],
- inner_measurement=rateE[1], dt=dt), -1, 1)
- yaw_output = np.clip(self.yaw_controller.update(outer_setpoint=(step // num_steps) * 0.5 * 0.0174533,
- outer_measurement=angEuler[2],
- inner_measurement=rateE[2], dt=dt), -1, 1)
- thrust = np.clip(-altitude_output + self.params.THR_HOVER, 0.05, 0.9)
- print('roll_output,pitch_output,yaw_output,altitude_output:', roll_output, pitch_output, yaw_output,
- altitude_output)
- M1, M2, M3, M4 = self.motor_mixer(roll_output, pitch_output, yaw_output, thrust)
- print('M1,M2,M3,M4:', M1, M2, M3, M4)
-
- w_target = (np.array(
- [self.pwm_to_rpm(M1), self.pwm_to_rpm(M2), self.pwm_to_rpm(M3),
- self.pwm_to_rpm(M4)]) * ModelParam_motorCr +
- np.array([ModelParam_motorWb, ModelParam_motorWb, ModelParam_motorWb, ModelParam_motorWb]))
- print('w_target:', w_target)
- state = self.dynamics.update_dynamics(state, w_target, dt)
- velB, angEuler, rateB = state
- # R = rotation_matrix(angEuler)
- R_angle = angle_body2world(angEuler)
- R = rotation_matrix(angEuler)
- rateE = R_angle @ rateB
- angEuler = angEuler + rateE * dt
- velE = R @ velB
- posE = posE + velE * dt
-
- state = velB, angEuler, rateB
- self.position_history.append(posE.copy())
- print(
- f"Time: {step * dt:.2f}s, Position: {posE}, Velocity_world: {velE}, Angle: {angEuler}, Rate: {rateE}")
- # if step % (next_corner_time-1) == 0 and step != 0:
- # current_corner_index = (current_corner_index + 1) % len(square_corners)
- self.setpoint_history.append(setpoint.copy())
-
- def plot_trajectory(self):
- position_history = np.array(self.position_history)
- setpoint_history = np.array(self.setpoint_history)
- fig = plt.figure()
- ax = fig.add_subplot(121, projection='3d')
- ax.plot(position_history[:, 0], position_history[:, 1], -position_history[:, 2], label='UAV Trajectory')
- ax.set_xlabel('X Position (m)')
- ax.set_ylabel('Y Position (m)')
- ax.set_zlabel('Z Position (m)')
- ax.set_title('Trajectory of UAV ')
- ax.legend()
-
- ax = fig.add_subplot(122, projection='3d')
- ax.plot(setpoint_history[:, 0], setpoint_history[:, 1], -setpoint_history[:, 2], label='setpoint Trajectory')
- ax.set_xlabel('X Position (m)')
- ax.set_ylabel('Y Position (m)')
- ax.set_zlabel('Z Position (m)')
- ax.set_title(' Desired Trajectory ')
- ax.legend()
-
- def plot_state_error(self):
- if self.controller_type == 'PID':
- fig_position = plt.figure(figsize=(14, 4))
- self.x_controller.outer_controller.plot_error(fig_position, 0, title='x_position')
- self.y_controller.outer_controller.plot_error(fig_position, 1, title='y_position')
- self.height_controller.outer_controller.plot_error(fig_position, 2, title='height_position')
- fig_velocity = plt.figure(figsize=(14, 4))
- self.x_controller.inner_controller.plot_error(fig_velocity, 0, title='x_velocity')
- self.y_controller.inner_controller.plot_error(fig_velocity, 1, title='y_velocity')
- self.height_controller.inner_controller.plot_error(fig_velocity, 2, title='height_velocity')
- else:
- self.position_controller.plot_error('_position')
- self.velocity_controller.plot_error('_velocity')
-
- fig_angle = plt.figure(figsize=(14, 4))
-
- self.roll_controller.outer_controller.plot_error(fig_angle, 0, title='roll_angle')
- self.pitch_controller.outer_controller.plot_error(fig_angle, 1, title='pitch_angle')
- self.yaw_controller.outer_controller.plot_error(fig_angle, 2, title='yaw_angle')
- plt.tight_layout()
- fig_rate = plt.figure(figsize=(14, 4))
-
- self.roll_controller.inner_controller.plot_error(fig_rate, 0, title='roll_rate')
- self.pitch_controller.inner_controller.plot_error(fig_rate, 1, title='pitch_rate')
- self.yaw_controller.inner_controller.plot_error(fig_rate, 2, title='yaw_rate')
- plt.tight_layout()
- # plt.show()
-
-
- if __name__ == '__main__':
- params = UAVParameters()
- dynamics = UAVDynamics(params)
- # controller = CascadePIDController(PIDController(3.0, 0.0, 0.15), PIDController(0.15, 0.0, 0.03))
- # controller_type = "PID"
- # controller_type = "MPC"
- controller_type = "LQR"
- position_controller = None
- if controller_type == 'PID':
- position_controller = posion_pos_controller(params).position_controller()
- elif controller_type == 'LQR':
- # 定义位置环的状态空间模型
- A_pos = np.zeros((3, 3))
- B_pos = np.eye(3)
-
- Q_pos = np.eye(3) * 1.65
- R_pos = np.eye(3) * 4.0
-
- # 定义速度环的状态空间模型
- A_vel = np.zeros((3, 3))
- B_vel = np.eye(3)
-
- Q_vel = np.eye(3) * 10.0
- R_vel = np.eye(3) * 2.4
- pos_controller = LQRController(A_pos, B_pos, Q_pos, R_pos)
- vel_controller = LQRController(A_vel, B_vel, Q_vel, R_vel)
- position_controller = [pos_controller, vel_controller]
- elif controller_type == 'MPC':
- # 定义离散位置环的状态空间模型
- A_pos = np.eye(3)
- B_pos = np.eye(3) * 0.01
-
- Q_pos = np.eye(3) * 3.95
- R_pos = np.eye(3) * 0.6
-
- # 定义离散速度环的状态空间模型
- # A_vel = np.zeros((3, 3))
- A_vel = np.eye(3)
- B_vel = np.eye(3) * 0.01
-
- Q_vel = np.eye(3) * 12.0
- R_vel = np.eye(3) * 0.6
- pos_controller = MPCController(A_pos, B_pos, None, 10, Q_pos, R_pos, -3, 3)
- vel_controller = MPCController(A_vel, B_vel, None, 10, Q_vel, R_vel, -1, 1)
- position_controller = [pos_controller, vel_controller]
- else:
- print('ERROR:Unknown Controller')
-
- pose_controller = posion_pos_controller(params).pos_controller()
- target_altitude = -5 # 目标高度
- square_corners = [
- [0, 0, 0],
- [0, 0, target_altitude],
- [5, 0, target_altitude],
- [5, 5, target_altitude],
- [0, 5, target_altitude],
- [0, 0, target_altitude],
- [0, 0, 0],
- [0, 0, 0]
- ]
- simulation = UAVSimulation(params, dynamics, position_controller=position_controller,
- pose_controller=pose_controller, controller_type=controller_type)
- simulation.run(square_corners, 35, 0.01)
- simulation.plot_trajectory()
- simulation.plot_state_error()
- plt.show()
三种控制算法效果如下:
可能由于任务较为简单,三种算法差异不大,同时LQR和MPC计算效率较低。
</div><div data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/perfectdisaster/article/details/143432386","extend1":"pc","ab":"new"}"><div></div></div>
</div>