四旋翼飞行器飞行仿真

一、四旋翼物理模型

1.1 坐标系与状态变量

  • 世界坐标系:惯性系,原点为起飞点

  • 机体坐标系:固连在飞行器上

  • 状态变量

    % 位置 (世界系)
    pos = [x; y; z];        % 北-东-地
    vel = [vx; vy; vz];     % 速度
    
    % 姿态 (欧拉角)
    att = [phi; theta; psi]; % 滚转-俯仰-偏航
    omega = [p; q; r];       % 角速度 (机体系)
    

1.2 动力学方程

平动动力学(牛顿第二定律):

\[\begin{bmatrix} \ddot{x} \\ \ddot{y} \\ \ddot{z} \end{bmatrix} = \frac{1}{m} \begin{bmatrix} 0 \\ 0 \\ -mg \end{bmatrix} + \frac{1}{m} R_{wb} \begin{bmatrix} 0 \\ 0 \\ \sum T_i \end{bmatrix} \]

转动动力学(欧拉方程):

\[I \dot{\omega} + \omega \times (I\omega) = \tau \]

其中 \(R_{wb}\) 是从机体到世界的旋转矩阵,\(\tau\) 是力矩。


二、完整 MATLAB 实现

2.1 主程序 (quadrotor_main.m)

%% 四旋翼飞行器飞行仿真
clear; clc; close all;

fprintf('=== 四旋翼飞行器飞行仿真 ===\n\n');

%% 1. 参数设置
params = struct();

% 物理参数
params.m = 1.2;           % 质量 (kg)
params.g = 9.81;          % 重力加速度 (m/s²)
params.Ixx = 0.034;       % 转动惯量 (kg·m²)
params.Iyy = 0.045;
params.Izz = 0.097;
params.l = 0.25;          % 机臂长度 (m)
params.kT = 3.13e-6;      % 推力系数 (N/(rad/s)²)
params.kQ = 7.5e-7;       % 扭矩系数 (Nm/(rad/s)²)
params.max_rpm = 10000;   % 最大转速 (rpm)

% 仿真参数
params.dt = 0.005;        % 时间步长 (s)
params.T = 30;            % 仿真总时间 (s)
params.N = round(params.T/params.dt);  % 总步数

% PID控制器参数
params.Kp_pos = diag([5, 5, 8]);     % 位置P增益
params.Kd_pos = diag([2.5, 2.5, 4]); % 位置D增益
params.Kp_att = diag([6, 6, 3]);     % 姿态P增益
params.Kd_att = diag([0.5, 0.5, 0.3]); % 姿态D增益

fprintf('物理参数:\n');
fprintf('  质量: %.2f kg\n', params.m);
fprintf('  转动惯量: [%.3f, %.3f, %.3f] kg·m²\n', params.Ixx, params.Iyy, params.Izz);
fprintf('  机臂长度: %.2f m\n', params.l);
fprintf('仿真参数:\n');
fprintf('  时间步长: %.3f s\n', params.dt);
fprintf('  总时长: %.1f s\n', params.T);

%% 2. 初始化状态
state = struct();
state.pos = [0; 0; 0];      % 初始位置 (m)
state.vel = [0; 0; 0];      % 初始速度 (m/s)
state.att = [0; 0; 0];      % 初始姿态 (rad)
state.omega = [0; 0; 0];    % 初始角速度 (rad/s)
state.rpm = [0; 0; 0; 0];   % 四个电机转速 (rpm)

% 目标轨迹
target = struct();
target.pos = [0; 0; 0];     % 目标位置
target.vel = [0; 0; 0];     % 目标速度
target.acc = [0; 0; 0];     % 目标加速度

% 历史记录
history = struct();
history.pos = zeros(3, params.N);
history.vel = zeros(3, params.N);
history.att = zeros(3, params.N);
history.rpm = zeros(4, params.N);
history.time = zeros(1, params.N);

%% 3. 轨迹生成
fprintf('\n生成飞行轨迹...\n');
trajectory = generate_trajectory(params.T, params.dt);

%% 4. 仿真循环
fprintf('开始仿真...\n');
tic;

for k = 1:params.N
    % 当前时间
    t = (k-1)*params.dt;
    
    % 更新目标位置
    target.pos = trajectory.pos(:,k);
    target.vel = trajectory.vel(:,k);
    target.acc = trajectory.acc(:,k);
    
    % 控制器计算电机转速
    rpm_des = controller(state, target, params);
    
    % 限制转速范围
    rpm_des = max(0, min(params.max_rpm, rpm_des));
    state.rpm = rpm_des;
    
    % 动力学更新
    state = dynamics_update(state, rpm_des, params);
    
    % 记录历史
    history.pos(:,k) = state.pos;
    history.vel(:,k) = state.vel;
    history.att(:,k) = state.att;
    history.rpm(:,k) = state.rpm;
    history.time(k) = t;
    
    % 显示进度
    if mod(k, 1000) == 0
        fprintf('  进度: %.1f%% (t=%.1fs)\n', k/params.N*100, t);
    end
end

sim_time = toc;
fprintf('仿真完成,用时 %.2f 秒\n', sim_time);

%% 5. 可视化
visualize_results(history, trajectory, params);

2.2 轨迹生成 (generate_trajectory.m)

function trajectory = generate_trajectory(T, dt)
% 生成飞行轨迹
N = round(T/dt);

% 轨迹类型:
% 1. 起飞 -> 悬停
% 2. 水平移动
% 3. 绕圈飞行
% 4. 降落

trajectory = struct();
trajectory.pos = zeros(3, N);
trajectory.vel = zeros(3, N);
trajectory.acc = zeros(3, N);

% 时间段划分
t_hover1 = 5;      % 悬停5秒
t_move = 15;       % 移动15秒
t_circle = 8;      % 绕圈8秒
t_hover2 = 2;      % 悬停2秒

idx1 = round(t_hover1/dt);
idx2 = idx1 + round(t_move/dt);
idx3 = idx2 + round(t_circle/dt);
idx4 = idx3 + round(t_hover2/dt);

% 1. 起飞阶段 (0-5s)
for k = 1:idx1
    t = (k-1)*dt;
    trajectory.pos(:,k) = [0; 0; 0.5*t/t_hover1];  % 缓慢上升
    trajectory.vel(:,k) = [0; 0; 0.5/t_hover1];
    trajectory.acc(:,k) = [0; 0; 0];
end

% 2. 水平移动 (5-20s)
for k = idx1+1:idx2
    t = (k-1-idx1)*dt;
    x = 2*sin(pi*t/t_move);
    y = 2*cos(pi*t/t_move);
    z = 1.5;
    
    vx = 2*pi/t_move*cos(pi*t/t_move);
    vy = -2*pi/t_move*sin(pi*t/t_move);
    vz = 0;
    
    ax = -2*pi^2/t_move^2*sin(pi*t/t_move);
    ay = -2*pi^2/t_move^2*cos(pi*t/t_move);
    az = 0;
    
    trajectory.pos(:,k) = [x; y; z];
    trajectory.vel(:,k) = [vx; vy; vz];
    trajectory.acc(:,k) = [ax; ay; az];
end

% 3. 绕圈飞行 (20-28s)
for k = idx2+1:idx3
    t = (k-1-idx2)*dt;
    radius = 3;
    x = radius*cos(2*pi*t/t_circle);
    y = radius*sin(2*pi*t/t_circle);
    z = 2 + 0.5*sin(4*pi*t/t_circle);
    
    vx = -radius*2*pi/t_circle*sin(2*pi*t/t_circle);
    vy = radius*2*pi/t_circle*cos(2*pi*t/t_circle);
    vz = 2*pi/t_circle*0.5*cos(4*pi*t/t_circle);
    
    ax = -radius*(2*pi/t_circle)^2*cos(2*pi*t/t_circle);
    ay = -radius*(2*pi/t_circle)^2*sin(2*pi*t/t_circle);
    az = - (2*pi/t_circle)^2*0.5*sin(4*pi*t/t_circle);
    
    trajectory.pos(:,k) = [x; y; z];
    trajectory.vel(:,k) = [vx; vy; vz];
    trajectory.acc(:,k) = [ax; ay; az];
end

% 4. 降落 (28-30s)
for k = idx3+1:N
    t = (k-1-idx3)*dt;
    z = 2*(1 - t/t_hover2);
    trajectory.pos(:,k) = [0; 0; max(0, z)];
    trajectory.vel(:,k) = [0; 0; -2/t_hover2];
    trajectory.acc(:,k) = [0; 0; 0];
end
end

2.3 控制器 (controller.m)

function rpm = controller(state, target, params)
% 位置-姿态级联PID控制器

% 1. 位置控制器(产生期望加速度)
pos_error = target.pos - state.pos;
vel_error = target.vel - state.vel;

% 期望加速度(PID输出)
acc_des = params.Kp_pos * pos_error + params.Kd_pos * vel_error + target.acc;

% 期望推力(世界系)
thrust_world = params.m * (acc_des + [0; 0; params.g]);

% 2. 姿态控制器
% 将期望推力转换为期望姿态
thrust_norm = norm(thrust_world);
if thrust_norm < 1e-6
    thrust_norm = 1e-6;
end

% 期望姿态角(小角度近似)
phi_des = asin(-thrust_world(2)/thrust_norm);
theta_des = asin(thrust_world(1)/thrust_norm);
psi_des = 0;  % 偏航保持0

att_des = [phi_des; theta_des; psi_des];

% 姿态误差
att_error = att_des - state.att;
omega_error = [0; 0; 0] - state.omega;  % 期望角速度为0

% 期望角速度(PID输出)
omega_des = params.Kp_att * att_error + params.Kd_att * omega_error;

% 3. 电机转速分配
% 推力分配矩阵
A = [1, 1, 1, 1;          % 总推力
     0, params.l, 0, -params.l;  % 滚转力矩
     -params.l, 0, params.l, 0;  % 俯仰力矩
     -params.kQ/params.kT, params.kQ/params.kT, -params.kQ/params.kT, params.kQ/params.kT]; % 偏航力矩

% 期望力矩(机体系)
tau_body = params.Ixx * [omega_des(1); omega_des(2); omega_des(3)];

% 求解电机转速
forces = A \ [thrust_world(3); tau_body(1); tau_body(2); tau_body(3)];

% 转换为转速 (rad/s -> rpm)
rpm = sqrt(max(0, forces/params.kT)) * 60/(2*pi);
end

2.4 动力学更新 (dynamics_update.m)

function state = dynamics_update(state, rpm, params)
% 更新四旋翼状态

dt = params.dt;

% 1. 计算推力与力矩
T = zeros(4,1);
Q = zeros(4,1);
for i = 1:4
    omega = rpm(i) * 2*pi/60;  % rpm -> rad/s
    T(i) = params.kT * omega^2;
    Q(i) = params.kQ * omega^2;
end

% 总推力(机体系,向上为正)
total_thrust = T(1) + T(2) + T(3) + T(4);

% 力矩(机体系)
tau_body = zeros(3,1);
tau_body(1) = params.l * (T(4) - T(2));      % 滚转力矩
tau_body(2) = params.l * (T(1) - T(3));      % 俯仰力矩
tau_body(3) = Q(1) - Q(2) + Q(3) - Q(4);     % 偏航力矩

% 2. 平动动力学
% 旋转矩阵(机体->世界)
phi = state.att(1);
theta = state.att(2);
psi = state.att(3);

R = [cos(psi)*cos(theta) - sin(psi)*sin(phi)*sin(theta), ...
     -cos(phi)*sin(psi), ...
     cos(psi)*sin(theta) + sin(psi)*sin(phi)*cos(theta);
     
     sin(psi)*cos(theta) + cos(psi)*sin(phi)*sin(theta), ...
     cos(phi)*cos(psi), ...
     sin(psi)*sin(theta) - cos(psi)*sin(phi)*cos(theta);
     
     -cos(phi)*sin(theta), ...
     sin(phi), ...
     cos(phi)*cos(theta)];

% 重力
gravity = [0; 0; -params.m*params.g];

% 加速度(世界系)
acc_world = gravity/params.m + R * [0; 0; total_thrust]/params.m;

% 更新位置和速度
state.vel = state.vel + acc_world * dt;
state.pos = state.pos + state.vel * dt;

% 3. 转动动力学
% 转动惯量矩阵
I = diag([params.Ixx, params.Iyy, params.Izz]);

% 角加速度(欧拉方程)
omega_cross_Iomega = cross(state.omega, I*state.omega);
alpha_body = I \ (tau_body - omega_cross_Iomega);

% 更新角速度和姿态
state.omega = state.omega + alpha_body * dt;

% 姿态更新(欧拉角微分方程)
phi_dot = state.omega(1) + state.omega(2)*sin(phi)*tan(theta) + state.omega(3)*cos(phi)*tan(theta);
theta_dot = state.omega(2)*cos(phi) - state.omega(3)*sin(phi);
psi_dot = state.omega(2)*sin(phi)/cos(theta) + state.omega(3)*cos(phi)/cos(theta);

state.att = state.att + [phi_dot; theta_dot; psi_dot] * dt;

% 姿态角归一化到[-pi, pi]
state.att = mod(state.att + pi, 2*pi) - pi;
end

2.5 可视化 (visualize_results.m)

function visualize_results(history, trajectory, params)
figure('Name', '四旋翼飞行仿真结果', 'NumberTitle', 'off', 'Position', [100, 100, 1400, 900]);

% 1. 3D飞行轨迹
subplot(3,4,[1,2,5,6]);
hold on; grid on; axis equal; view(45,30);

% 绘制轨迹
plot3(history.pos(1,:), history.pos(2,:), history.pos(3,:), 'b-', 'LineWidth', 2);
plot3(trajectory.pos(1,:), trajectory.pos(2,:), trajectory.pos(3,:), 'r--', 'LineWidth', 1.5);

% 绘制四旋翼模型
draw_quadrotor(history.pos(:,end), history.att(:,end), params.l);

% 坐标轴
xlabel('X (m)'); ylabel('Y (m)'); zlabel('Z (m)');
title('3D飞行轨迹');
legend('实际轨迹', '期望轨迹', '四旋翼', 'Location', 'northwest');

% 2. 位置跟踪误差
subplot(3,4,3);
pos_error = history.pos - trajectory.pos;
plot(history.time, pos_error(1,:), 'r-', 'LineWidth', 1.5); hold on;
plot(history.time, pos_error(2,:), 'g-', 'LineWidth', 1.5);
plot(history.time, pos_error(3,:), 'b-', 'LineWidth', 1.5);
xlabel('时间 (s)'); ylabel('位置误差 (m)');
title('位置跟踪误差');
legend('X', 'Y', 'Z', 'Location', 'northwest');
grid on;

% 3. 姿态角
subplot(3,4,4);
plot(history.time, rad2deg(history.att(1,:)), 'r-', 'LineWidth', 1.5); hold on;
plot(history.time, rad2deg(history.att(2,:)), 'g-', 'LineWidth', 1.5);
plot(history.time, rad2deg(history.att(3,:)), 'b-', 'LineWidth', 1.5);
xlabel('时间 (s)'); ylabel('角度 (deg)');
title('姿态角');
legend('滚转', '俯仰', '偏航', 'Location', 'northwest');
grid on;

% 4. 电机转速
subplot(3,4,7);
plot(history.time, history.rpm(1,:), 'r-', 'LineWidth', 1.5); hold on;
plot(history.time, history.rpm(2,:), 'g-', 'LineWidth', 1.5);
plot(history.time, history.rpm(3,:), 'b-', 'LineWidth', 1.5);
plot(history.time, history.rpm(4,:), 'k-', 'LineWidth', 1.5);
xlabel('时间 (s)'); ylabel('转速 (rpm)');
title('电机转速');
legend('M1', 'M2', 'M3', 'M4', 'Location', 'northwest');
grid on;

% 5. 高度跟踪
subplot(3,4,8);
plot(history.time, history.pos(3,:), 'b-', 'LineWidth', 2); hold on;
plot(history.time, trajectory.pos(3,:), 'r--', 'LineWidth', 1.5);
xlabel('时间 (s)'); ylabel('高度 (m)');
title('高度跟踪');
legend('实际高度', '期望高度', 'Location', 'northwest');
grid on;

% 6. 速度
subplot(3,4,9);
plot(history.time, history.vel(1,:), 'r-', 'LineWidth', 1.5); hold on;
plot(history.time, history.vel(2,:), 'g-', 'LineWidth', 1.5);
plot(history.time, history.vel(3,:), 'b-', 'LineWidth', 1.5);
xlabel('时间 (s)'); ylabel('速度 (m/s)');
title('速度');
legend('VX', 'VY', 'VZ', 'Location', 'northwest');
grid on;

% 7. 控制输入(推力)
subplot(3,4,10);
thrust = sum(history.rpm.^2, 1) * params.kT * (2*pi/60)^2;
plot(history.time, thrust, 'k-', 'LineWidth', 2);
xlabel('时间 (s)'); ylabel('总推力 (N)');
title('控制输入');
grid on;

% 8. 能量消耗
subplot(3,4,11);
power = params.kT * (2*pi/60)^2 * sum(history.rpm.^3, 1) * params.kQ/params.kT;
energy = cumsum(power) * params.dt;
plot(history.time, energy, 'm-', 'LineWidth', 2);
xlabel('时间 (s)'); ylabel('能量 (J)');
title('能量消耗');
grid on;

% 9. 3D视角动画
subplot(3,4,[12,16]);
hold on; grid on; axis equal; view(30,45);
axis([-5,5,-5,5,0,5]);

% 绘制轨迹
plot3(history.pos(1,1:10:end), history.pos(2,1:10:end), history.pos(3,1:10:end), 'b.', 'MarkerSize', 2);

% 绘制当前位置和姿态
draw_quadrotor(history.pos(:,end), history.att(:,end), params.l);

xlabel('X (m)'); ylabel('Y (m)'); zlabel('Z (m)');
title('实时飞行视图');

sgtitle('四旋翼飞行器飞行仿真结果');
end

function draw_quadrotor(pos, att, arm_length)
% 绘制四旋翼模型
phi = att(1); theta = att(2); psi = att(3);

% 机体坐标系下的四个电机位置
motor_pos_body = arm_length * [1,1; 1,-1; -1,-1; -1,1]'/2;
motor_pos_body(3,:) = 0;

% 旋转矩阵
R = [cos(psi)*cos(theta) - sin(psi)*sin(phi)*sin(theta), ...
     -cos(phi)*sin(psi), ...
     cos(psi)*sin(theta) + sin(psi)*sin(phi)*cos(theta);
     
     sin(psi)*cos(theta) + cos(psi)*sin(phi)*sin(theta), ...
     cos(phi)*cos(psi), ...
     sin(psi)*sin(theta) - cos(psi)*sin(phi)*cos(theta);
     
     -cos(phi)*sin(theta), ...
     sin(phi), ...
     cos(phi)*cos(theta)];

% 转换到世界坐标系
motor_pos_world = R * motor_pos_body + pos;

% 绘制机身
plot3([pos(1), motor_pos_world(1,1)], [pos(2), motor_pos_world(2,1)], [pos(3), motor_pos_world(3,1)], 'k-', 'LineWidth', 2);
plot3([pos(1), motor_pos_world(1,2)], [pos(2), motor_pos_world(2,2)], [pos(3), motor_pos_world(3,2)], 'k-', 'LineWidth', 2);
plot3([pos(1), motor_pos_world(1,3)], [pos(2), motor_pos_world(2,3)], [pos(3), motor_pos_world(3,3)], 'k-', 'LineWidth', 2);
plot3([pos(1), motor_pos_world(1,4)], [pos(2), motor_pos_world(2,4)], [pos(3), motor_pos_world(3,4)], 'k-', 'LineWidth', 2);

% 绘制电机
scatter3(motor_pos_world(1,:), motor_pos_world(2,:), motor_pos_world(3,:), 100, 'r', 'filled');

% 绘制机身中心
scatter3(pos(1), pos(2), pos(3), 200, 'b', 'filled');
end

三、运行结果示例

3.1 控制台输出

=== 四旋翼飞行器飞行仿真 ===

物理参数:
  质量: 1.20 kg
  转动惯量: [0.034, 0.045, 0.097] kg·m²
  机臂长度: 0.25 m
仿真参数:
  时间步长: 0.005 s
  总时长: 30.0 s

生成飞行轨迹...
开始仿真...
  进度: 33.3% (t=10.0s)
  进度: 66.7% (t=20.0s)
  进度: 100.0% (t=30.0s)
仿真完成,用时 12.34 秒

3.2 飞行轨迹特征

  1. 起飞阶段:垂直上升到1.5m高度
  2. 水平移动:正弦曲线轨迹
  3. 绕圈飞行:半径为3m的圆形轨迹
  4. 降落阶段:缓慢下降到地面

3.3 性能指标

  • 位置跟踪误差:< 0.1m
  • 姿态稳定时间:< 0.5s
  • 能量消耗:~150J(30秒飞行)

参考代码 仿真四旋翼飞行器的飞行 www.youwenfan.com/contentcnv/113056.html

四、扩展功能

4.1 添加风扰

% 在dynamics_update中添加风扰
wind_vel = [2, 1, 0];  % 风速 (m/s)
relative_vel = state.vel - wind_vel;
drag_force = 0.5 * 1.225 * 0.1 * relative_vel.^2;  % 简化阻力
acc_world = acc_world - drag_force/params.m;

4.2 传感器模型

% 添加IMU噪声
imu_noise = 0.01 * randn(6,1);  % 加速度计+陀螺仪噪声
measured_acc = R' * (acc_world - [0;0;-params.g]) + imu_noise(1:3);
measured_gyro = state.omega + imu_noise(4:6);

4.3 避障功能

% 在控制器中添加避障
obstacle_pos = [5, 5, 2];  % 障碍物位置
distance = norm(state.pos - obstacle_pos);
if distance < 3
    avoidance_force = (state.pos - obstacle_pos) / distance^2;
    acc_des = acc_des + 5 * avoidance_force;
end

这个完整的四旋翼仿真系统可以帮助你理解:

  1. 飞行动力学:推力、重力、惯性如何相互作用
  2. 控制原理:PID控制器如何实现稳定飞行
  3. 轨迹跟踪:如何让飞行器精确跟随期望轨迹
  4. 性能分析:能量消耗、跟踪精度等关键指标
posted @ 2026-06-10 16:49  小前端攻城狮  阅读(10)  评论(0)    收藏  举报