ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Matlab小型固定翼无人机仿真:六自由度建模、路径规划与PID调试全解析

Matlab小型固定翼无人机仿真:六自由度建模、路径规划与PID调试全解析

简介:Matlab小型固定翼无人机建模与仿真程序,涵盖动力系统、飞行力学与控制系统建模,并集成图像显示与路径规划功能。资源基于Matlab/Simulink平台,适合航空、机器人领域学生及无人机开发者学习参考,可用于理解无人机自主飞行的完整仿真链路。压缩包共34个文件,主要包括28个m脚本、3个slx模型、2张jpg图片和1张png图,m脚本覆盖建模仿真、路径规划、控制律设计等核心环节,slx模型可直接运行仿真,图片用于环境或目标展示,整体仅540KB,轻量易用。已有1101人学习下载。内容包含完整仿真框架与可运行代码,如基于Dubins路径的RRT规划、制导与控制模型、传感器与状态估计等,并附有trim配平与线性化模型,便于二次开发与实验验证。

1. 为什么偏偏是小型固定翼:这台 Matlab 无人机仿真能帮你跑通什么

做了几年无人机相关项目后,你会发现一个尴尬事实:网上能下载到的固定翼无人机仿真程序,要么是塞满 Simulink 模块但没几行注释的“黑匣子”,要么是只能画个二维航线、完全不带动力学的地面站演示。而这份资源最打动我的地方,是它把“小型固定翼无人机的建模与仿真”做成了三件套——六自由度动力学模型、路径规划、图像显示,全部用 Matlab 脚本串起来,不需要额外的无人机工具箱也能跑通。对正在做 matlab 无人机仿真课设、毕业设计,或者想快速验证飞控和航迹算法的人来说,它相当于一份能直接改参数、直接看飞行姿态和轨迹的完整 demo。你不需要先啃完一整本《飞机飞行力学》才能动手,模型虽然简化但五脏俱全:气动力、推力、重力、力矩方程都在,路径规划也不是摆样子的 A 到 B 直线,而是带转弯约束的规划输出,仿真结果通过图像面板实时显示姿态角、位置和航迹。接下来我把文件结构、建模方程、规划算法和踩过的坑一条条拆开。

2. 先看模型再谈仿真:固定翼六自由度方程与程序结构

2.1 固定翼建模的坐标系约定

固定翼和四旋翼最大的区别在于:它靠前向速度产生升力,姿态变化和气动力强耦合,建模时坐标系必须一开始就定死,否则后面每条曲线都是错的。这套程序里使用的是标准机体坐标系,X 轴指向机头,Y 轴指向右翼,Z 轴向下,原点在重心。这个约定和市面上多数飞控固件一致,方便你后续把仿真的姿态输出直接对接 Pixhawk 等硬件。

坐标系定了之后,紧接着要处理的是欧拉角的旋转顺序。程序里采用 Z-Y-X 的顺序,即先偏航角 Psi、再俯仰角 Theta、最后滚转角 Phi。这个顺序在航空航天领域是默认惯例,我在用别的开源代码时发现很多人图省事用 Z-X-Y,结果滚转和偏航在仿真中相互耦合,调参时怎么都调不平直飞行段。

这段模型的核心状态量是 12 个:位置 3 个(北东地坐标系下的 xN、yE、zD),速度 3 个(机体系下的 u、v、w),姿态 3 个(Phi、Theta、Psi),角速度 3 个(p、q、r)。程序里所有方程都是围绕这 12 个状态量展开的。

% 状态向量定义: 前三个为NED位置, 四五六为机体速度, 七八九为欧拉角, 十到十二为角速度 % 单位均为国际标准: 米, 米/秒, 弧度, 弧度/秒 x0 = [0; 0; -100; % 初始位置: 北0米, 东0米, 高度100米 25; 0; 0; % 初始机体速度: 前向25m/s 0; 0.05; 0; % 初始姿态: 几乎水平, 略抬机头 0; 0; 0]; % 初始角速度

上面这段初始化揭示了两个关键设置:巡航速度 25 m/s 对应典型的 1.2 米翼展小型固定翼无人机,初始高度 100 米则是为了给路径规划和避障留出安全余量。如果你要改机型,最需要动的就是第一组位置和速度的初值,而不是去改气动系数,因为气动系数的量级在小迎角范围内基本是稳定的。

2.2 气动力与力矩的计算逻辑

程序的力与力矩计算分布在独立的脚本里,输入是当前状态和控制量,输出是合外力与合力矩。升力系数 CL、阻力系数 CD、侧力系数 CY 分别按线性气动模型计算,这是小型无人机建模最常见的选择,因为它比查表法简单得多,又比完全忽略气动细节的质点模型真实得多。

function [F, M] = aero_forces_moments(state, delta, aircraft) % 拆解状态量 u = state(4); v = state(5); w = state(6); phi = state(7); theta = state(8); psi = state(9); p = state(10); q = state(11); r = state(12); % 计算迎角和侧滑角 V = sqrt(u^2 + v^2 + w^2); alpha = atan2(w, u); % 迎角, 弧度 beta = atan2(v, V); % 侧滑角, 弧度 % 气动系数: 升力、阻力、侧力 CL = aircraft.CL0 + aircraft.CLa * alpha; CD = aircraft.CD0 + aircraft.CDa * alpha^2; CY = aircraft.CYb * beta; % 动压 qbar = 0.5 * aircraft.rho * V^2; % 气动力在风轴系, 转到机体系 L = qbar * aircraft.S * CL; D = qbar * aircraft.S * CD; Y = qbar * aircraft.S * CY; % 风轴到机体的旋转 Fa = [L*sin(alpha) - D*cos(alpha); Y; -L*cos(alpha) - D*sin(alpha)]; % 重力在机体系的投影 Fg = aircraft.m * 9.81 * [-sin(theta); sin(phi)*cos(theta); cos(phi)*cos(theta)]; % 推力默认沿机体X轴 Ft = [delta.throttle * aircraft.Tmax; 0; 0]; F = Fa + Fg + Ft; % 力矩计算: 副翼/升降舵/方向舵分别作用于滚转/俯仰/偏航 M = [qbar*aircraft.S*aircraft.b*aircraft.Clp*p + delta.aileron * qbar * aircraft.S * aircraft.b * aircraft.Clda; qbar*aircraft.S*aircraft.c*aircraft.Cmq*q + delta.elevator * qbar * aircraft.S * aircraft.c * aircraft.Cmde; qbar*aircraft.S*aircraft.b*aircraft.Cnr*r + delta.rudder * qbar * aircraft.S * aircraft.b * aircraft.Cndr]; end

代码里最值得注意的分两处。第一处是升力表达式中同时包含 CL0 和 CLa * alpha,巡航状态时 CL0 不为零,因为固定翼需要靠它平衡重力,如果照抄四旋翼的把 CL0 设成 0,仿真开始后飞机会立刻掉高度。第二处是力矩全部采用阻尼项加舵效项的组合,p、q、r 前面的系数是气动阻尼,舵面偏转量前面的系数是操纵导数,这两类参数的比例关系直接决定了飞机是“稳如老狗”还是“一碰就翻”。

2.3 程序文件结构速览

拿到手先别急着运行,花五分钟确认文件结构。主入口是main.m,负责设置参数、调用仿真循环、触发图像显示;dynamics.m是十二状态量的导数函数,供ode45调用;aero_forces_moments.m是上一节的气动力计算;path_planning.m生成预设航点;visualization.m负责三维轨迹和姿态显示。如果你看到control_law.m,那就是最简化的 PID 控制器,用来跟踪高度和航向。

参数集中在一个结构体aircraft里,包括翼展 b、机翼面积 S、平均气动弦长 c、质量 m、推力最大值 Tmax、气动系数等。我第一次跑的时候什么都看不懂,后来才发现这些参数加在一起,对应一架翼展约 1.2 米、起飞重量约 1.8 千克的小型电动固定翼,推重比大约在 0.6 左右,属于典型的低速教学机配置。

3. 把无人机三维路径规划落进代码:航点设计到 Dubins 路径衔接

3.1 路径规划到底规划了什么

很多做 matlab 无人机路径规划的人有个误区,以为路径规划就是生成一串经纬度点,然后让飞机依次飞过。但在固定翼仿真里,这一步必须额外回答一个问题:飞机以 25 m/s 巡航,转弯半径是多少?如果规划出来的航线转弯半径比飞机最小转弯半径还小,仿真中的控制器会拼命压坡度,结果就是掉高度或者失速。

这个程序里的路径规划模块,正是把“可飞性”放在第一位。它首先生成一组三维航点,然后对每两个航点之间的过渡段做圆弧平滑处理,圆弧半径可配置,默认值为 80 米,对应 25 m/s 速度下大约 20 度坡度的转弯。平滑之后,路径从“折线”变成“圆弧+直线”的组合,这个思路和真实飞行管理系统里的航段构建方式一致。

% 生成航点表: 每行是 北, 东, 高度 waypoints = [0, 0, -100; 300, 0, -100; 300, 300, -120; 600, 300, -120; 600, 600, -100]; % 配置转弯半径, 单位米 turn_radius = 80; % 调用路径平滑: 对每个转弯点插入圆弧过渡段 [path_x, path_y, path_z] = smooth_path_with_arc(waypoints, turn_radius); % 输出规划路径总长度 total_len = sum(sqrt(diff(path_x).^2 + diff(path_y).^2 + diff(path_z).^2)); fprintf('规划路径总长度: %.1f 米\n', total_len);

这段代码里的smooth_path_with_arc是核心,它的作用不是简单插值,而是根据前后两个航段的几何关系,计算切点在原航段上的位置,然后以给定半径生成一段圆弧。竖直方向的爬升/下滑段不做圆弧过渡,因为固定翼爬升率有限,陡峭的航段会让俯仰控制器饱和。

参数方面,turn_radius 设 80 米时,仿真里的飞机用 20 度左右坡度就可以跟住航线。如果你把半径改成 40 米,飞机就需要 35 度以上的坡度来跟随,这在小迎角线性气动模型里已经接近线性范围边缘,姿态显示中会出现明显的侧滑。

3.2 路径规划、制导与动力学模型的三个衔接点

很多人仿真翻车,问题不在模型本身,而在模块衔接。这个程序里依次有规划层、制导层、动力学层三层,衔接点一共三个:规划路径输出离散点,制导层根据当前飞机位置找最近点生成期望航向角,控制器再把这个航向角换算成滚转角指令。这三层的接口变量名如果对不上,程序直接报错;如果对上了但坐标系不一致,程序不报错但飞机会画出诡异轨迹。

% 制导逻辑: 找当前路径上的最近点, 计算期望方位角 function [desired_psi] = guidance_psi(xN, xE, path_x, path_y) dist2 = (path_x - xN).^2 + (path_y - xE).^2; [~, idx] = min(dist2); % 最近点索引 forward_idx = min(idx + 2, length(path_x)); % 向前看两个点 % 期望航向角由前视点与当前位置的连线确定 desired_psi = atan2(path_y(forward_idx) - xE, ... path_x(forward_idx) - xN); end

这里有一个常被忽略的细节:找最近点时用的是当前位置与全部路径点的距离,在长路径下计算量大,但因为是脚本仿真,上百个点也就毫秒级计算,不是瓶颈。真正重要的是前视索引forward_idx = idx + 2,这个“向前看两个点”的机制模仿了制导律里的前视距离,它让飞机不会等到了转弯点才压坡度,而是在转弯点之前就开始预转弯。这个参数直接影响航迹跟踪误差:设得太小,飞机切弯时会超调;设得太大,会提前转弯导致横滚方向与期望路径交叉。

3.3 图像显示里最容易看漏的指标

程序的图像显示分成三个子窗口:三维航迹图、姿态指示器、以及一组实时曲线。三维航迹图把规划路径画成灰色虚线,把实际飞行轨迹画成蓝色实线,两条线越贴近,说明导航控制器性能越好。姿态指示器模拟了仪表盘上的人工地平仪,滚转和俯仰一目了然。

我建议你仿真结束后多看一个东西:实际轨迹与规划路径的横向偏差曲线。这个曲线不是图像显示默认输出,但你可以从运行日志中提取位置序列后自行计算。如果偏差一直稳定在 5 米以内,说明整个链路参数匹配;如果偏差持续增长,首先怀疑的不是控制器增益,而是风场模型——对,这个程序里带了一个可开关的常值风场项,在风场开启时没有把前视距离加大,航迹偏差会比无风时大一倍以上。

4. 把整套仿真跑起来:从主循环到姿态显示的完整闭环

4.1 主程序架构与控制流

程序主循环采用标准的时间步进仿真:先用ode45以连续时间方式推进动力学,再在每一步结束时采样位置姿态并送入图像刷新。这种“离散画图、连续积分”的组合是 Matlab 无人机仿真的常见做法,比 Simulink 的固定步长仿真更灵活,也比完全离散化的欧拉积分更精确。

% 主仿真入口: 时长20秒, 时间步长0.05秒 t_end = 20; dt = 0.05; tspan = 0:dt:t_end; % 预分配记录矩阵 state_log = zeros(length(tspan), 12); xN_log = zeros(length(tspan), 1); yE_log = zeros(length(tspan), 1); % 初始化状态 state = x0; for k = 1:length(tspan) % 根据当前时刻对应的参考路径计算控制量 % 控制拆成高度保持与航向跟踪两层 delta = compute_control(state, path_data, tspan(k)); % 单步积分: 用ode45推进一个步长 [~, state_next] = ode45(@(t, s) dynamics(t, s, delta, aircraft), ... [tspan(k), tspan(k)+dt], state); state = state_next(end, :)'; % 记录当前状态 state_log(k, :) = state'; xN_log(k) = state(1); yE_log(k) = state(2); end % 显示三维航迹 visualize_3d_track(xN_log, yE_log, -state_log(:,3), path_data);

这里compute_control接收的是当前状态和路径数据,返回舵面偏转与油门。控制律具体实现是高度偏差的比例控制加航向偏差的比例控制,再叠加滚转阻尼项。注意这里没有积分项,所以稳态误差是存在的——比如常值侧风下航向会有固定偏差。如果你想消除这个误差,修改compute_control增加一个积分状态即可,程序里已经留好了结构。

关于ode45的单步调用,我拆包时最初以为直接在整个 tspan 上跑一次就行,后来发现不行:控制量在每个积分步内需要保持常数,如果把整个仿真时长传给ode45,控制输入无法随时间更新。程序里这种“循环内单步积分”写法,正是为了在每个步长处刷新控制量而设计的,这是个很容易被忽略但极其重要的架构决策。

4.2 仿真参数调整对照表

拿到资源后你最需要的就是一张“哪里能改、改了会怎样”的对照表。以下参数直接决定仿真行为和结果形态,我按我的调整经验列出来。

参数初始值调整方向与效果适合场景
巡航速度 V025 m/s车速提高后转弯半径需要同步调大模拟更快的翼型
turn_radius80 m减小到 40 m 会让控制舵面更饱和模拟小场地机动
初始高度100 m高度太低时转弯掉高会碰地模拟低空巡检
CL00.25增大后平飞所需迎角减小高升力翼型
风场风速0(可开关)设定 5 m/s 侧风检验控制器鲁棒性抗风性能验证
PID 比例系数航向 0.8系数过大会导致滚转振荡且伴随掉高快速响应需求

这张表的调整逻辑有一条主线:所有参数的改动必须成组做。比如你提高了巡航速度,就必须同步增大 turn_radius 或提高航向 PID 比例系数,否则航迹跟踪会出现明显过冲。我在第一次试验时就只把速度从 25 调到 30,结果转弯半径不变,飞机沿路径飞行时侧滑角到了 8 度以上,姿态显示里坡度几乎压到 40 度。

4.3 PID 参数与轨迹跟踪的调试顺序

轨迹跟踪质量好坏,在图像显示上最直观的表现是:灰线和蓝线是否贴在一起。我的调试顺序是固定的三步。先调高度通道:关闭航向跟踪,只让飞机按直线路径飞,调高度 PID 使高度误差在 2 米以内。再调航向通道:保持高度控制,开启完整的航点飞行,观察每个转弯点的超调量,如果转弯后有 S 形摆动,就把比例系数往下压 20%。最后加大风场到 5 m/s,把航向环积分项加上,直到灰色路径与实际轨迹的横向偏差收敛。

这套顺序看起来简单,但绝大多数人一上来就把航向和高度的 PID 一起调,结果两个环互相干扰,参数怎么调都不收敛。我养成的习惯是每个环节只动一个参数,记录一次曲线,确认收敛后才碰下一个环。这个思路在状态空间模型里叫“分通道整定”,放在这个小程序里同样适用。

5. 避坑手册:固定翼仿真中四个最容易翻车的现场

5.1 海拔正负号:图像里飞机倒着飞

现象:仿真运行正常,但三维显示中飞机从 100 米“飞”到负 100 米,图像里机头朝上却逐渐远离地面。

原因:模型采用的是北东地坐标系,高度方向 Z 轴向下。初始高度设置为 -100 米才是正确的 100 米海拔。许多新手沿用了地面车辆仿真的习惯,认为高度为正数就是向上,结果把动力学中的重力方向搞反,飞机表现出的所有响应都镜像翻转。

解决:将状态向量第三位保持负值,图像显示调用时用-state(:,3)显示为正高度。路径规划模块中所有航点的第三列坐标也必须是负值,这个符号约定在waypoints表和smooth_path_with_arc函数内必须统一。

5.2 ode45 在特殊点计算极慢

现象:仿真卡在某一步停止推进,或这一段时间步长越变越小,运行时间突然从几秒涨到几分钟。

原因:ode45是变步长积分器,它会根据误差估计自动缩小步长。当控制量发生跳变或路径分段点出现在积分区间内时,导数函数会因切换点不连续而产生高频成分,导致积分器进入“步长缩小-误差超限”的循环。

解决:把仿真时长划分成若干连续段,在每段内保持控制量不变且无路径切换点,然后分段积分并把状态逐段传递。程序里其实已经隐式地按时间步做了拆分,如果你自己在改代码时又把ode45改成整个时间段一次性执行,就会遇到这个坑。

5.3 初始迎角不为零导致的瞬间俯冲

现象:仿真前 0.5 秒内飞机完成一次明显的低头又抬头,高度先降后升,姿态曲线出现尖峰。

原因:初始状态里速度向量沿机体 X 轴,但升力系数 CL0 对应一个不为零的平衡迎角。如果初始速度方向与机体轴完全一致,实际迎角为零,而 CL0 产生的升力不足以平衡重力,飞机立即下沉;随后控制器纠偏,产生一次过冲。

解决:按 CL0 反算配平迎角,初始状态的速度向量稍微给一个 z 分量。常见做法是把初始 w 设为 0.4 到 0.6 m/s 左右,对应大约 1 到 1.5 度的初始迎角,飞机从第一帧开始就处于近似平衡状态。如果不处理这个初始配平,你就只能接受前 0.5 秒的姿态抖动数据,并在论文中把它当作“瞬态响应”处理。

5.4 路径规划点转弯半径小于最小转弯半径

现象:航迹跟踪误差在转弯段突然增大到 20 米以上,姿态显示里坡度指令长期饱和在 30 度以上,飞行速度也在转弯段明显下降。

原因:规划的圆弧半径小于该速度下的最小转弯半径,控制器在“跟上航迹”与“保持高度”之间挣扎,最终两边都失控。

解决:先估算最小转弯半径,公式为 R_min = V^2 / (g * tan(phi_max))。以 V=25 m/s、phi_max=30 度估算,R_min 大约为 110 米。程序默认的 80 米其实偏小,它是在默认 20 度坡度下设计的,如果你不想改坡度限制,就把 turn_radius 至少调到 110 米以上。

6. 仿真时间换算与数据回放:验证模型正确性的一个硬核技巧

6.1 仿真时间与实际时间的关系

固定翼仿真里时间基准很关键。程序里仿真的 1 秒就是真实世界 1 秒,但这是指仿真时间轴上的积分推进,不代表你刷新屏幕、运行路径规划代码所耗费的墙钟时间。这在做半物理测试时尤其重要,你要把“模拟出的 20 秒飞行”和“运行脚本花了 3 秒”分开看待。

% 计算仿真时间与实时性的比值 t_start = tic; % ...运行主仿真循环... elapsed = toc(t_start); sim_time = t_end; fprintf('仿真时长: %.1f秒, 墙钟耗时: %.2f秒, 实时性: %.2fx\n', ... sim_time, elapsed, sim_time / elapsed);

这个实时性倍率是衡量程序是否适合做硬件在环的关键指标。如果倍率大于 1,说明仿真比真实时间快,适合批量参数扫描;如果倍率小于 1,说明计算量过大,你在做参数整定时得等很久。这个程序的倍率通常在 1.5 到 3 之间,如果低到 0.5 以下,优先检查是否前面的ode45踩了第 5.2 节的坑。

6.2 用记录数据回放检验模型一致性

很多人验证模型只看最终结果图,其实更硬核的验证方法是做一次数据回放:把state_log保存成 mat 文件,用另一段脚本读取后再画一整套姿态曲线,检查是否有“跳变”或“不连续”的瞬间。如果回放数据与实时显示不一致,说明显示模块与动力学模块之间出现了采样率或缓存问题。

% 将仿真记录存盘, 便于离线回放分析 save('flight_log.mat', 'state_log', 'tspan', 'path_data', 'aircraft'); % 离线回放: 绘制欧拉角变化曲线 load('flight_log.mat'); phi = state_log(:,7) * 180/pi; theta = state_log(:,8) * 180/pi; psi = state_log(:,9) * 180/pi; % 检查是否有不连续跳变 discontinuity = find(abs(diff(phi)) > 10); % 10度以上跳变 if ~isempty(discontinuity) fprintf('警告: 滚转角在以下时间点存在异常跳变: \n'); disp(tspan(discontinuity)); end

这个技巧的价值在于把“一次性仿真”变成“可复核的数据集”。我在做毕设的时候就是靠这个回放脚本,发现有一组参数下滚转角每隔 2 秒出现一次 15 度的跳变,再去查代码,发现是控制器里滚转角档位切换没有做无扰切换——这种问题从最终三维轨迹里根本看不出来,只有回放逐帧姿态曲线才看得清。

从那以后,我每次跑完任何无人机相关仿真,都会强制走一遍存盘回放流程,不会只盯着最终画面觉得差不多就行了。模型正确性用数据说话,比“看起来像真的”可靠得多。最后我想提醒的是:这个资源的价值在于它同时给了你模型、规划、显示三块内容,如果你只把它当作一个画轨迹的工具,那等于只用了它三分之一的能力。建议拿到手后先按默认参数仿真一遍,然后按我给的对照表逐项调整,体会每个参数对飞行品质的影响,这个流程走完,你才算真正“用起来”了这份资源。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进