1. 概述
该项目旨在构建一个用 Python 从零搭建的飞行器控制仿真系统,覆盖从刚体动力学建模、传感器仿真、组合导航、控制器设计到强化学习策略训练的完整链路。支持多旋翼(四/六/八旋翼,拓扑结构自动生成)与固定翼,考虑地球曲率效应与大气环境扰动。
1.1. 能力矩阵
以下表格列出本项目的核心能力维度与覆盖情况,方便不同背景的读者快速判断项目是否与自身需求相关:
| |
|---|
| 机型 | |
| 动力学 | 六自由度刚体动力学、地球曲率坐标系、四元数内部表示、RK4 积分 |
| 环境扰动 | 常值风、阵风、Dryden 湍流、风切变、重力场变化、大气密度/温度变化、地面效应 |
| 执行机构 | 舵机、电机、电调(一阶/二阶动力学 + 死区/饱和非线性) |
| 传感器仿真 | IMU(加速度计+陀螺仪)、气压计、GPS、空速管 |
| 组合导航 | EKF 松组合/紧组合、UKF、互补滤波、导航性能评估 |
| 传统控制器 | PID、LQR、MPC、ADRC、滑模控制(含超螺旋)、反步法 |
| 强化学习 | Gymnasium 标准接口、自定义训练循环、SB3 接口预留、可组合奖励函数、域随机化 |
| 轨迹规划 | 直线、圆弧、Minimum-Snap、B 样条、多项式轨迹、高度剖面规划 |
| 任务规划 | 飞行阶段自动切换(起飞→爬升→巡航→末制导→着陆) |
| 实时仿真 | |
| GUI | PySide6 交互界面,支持实时演示与参数在线调整 |
| 可视化 | 2D/3D 静态绘图(Matplotlib)、实时绘图(PyQtGraph/PyBullet) |
| 数据分析 | 时域/姿态/跟踪/控制/鲁棒性五大类指标、标准化报告输出 |
| 工程化 | Pydantic 类型校验、Numba 加速、pytest 测试、CI/CD、Docusaurus 文档 |
1.2. 典型使用场景
以下场景不代表项目的全部用途,仅为帮助理解其设计意图:
场景 A — 课程学习与毕业设计:一名航空航天专业的大四学生正在做四旋翼控制的毕业设计。他需要理解 PID 和 LQR 在同一仿真环境下的性能差异。通过配置文件切换控制器,运行一组蒙特卡洛仿真,数据分析模块自动生成包含跟踪误差、超调量、控制能耗的对比报告。
场景 B — 强化学习研究:一名 RL 研究者希望训练一个端到端的四旋翼自主降落策略。他将仿真环境注册为 Gymnasium 环境,设定域随机化范围(质量 ±20%、风速 0–5 m/s),用 PPO 算法进行训练。训练完成后,策略网络通过统一接口直接加载到仿真器中进行评估。
场景 C — 控制器鲁棒性评估:一名工程师需要评估自抗扰控制器(ADRC)在风切变条件下对固定翼航迹跟踪的鲁棒性。他开启环境模型中的 Dryden 湍流与风切变模块,将 ADRC 与 MPC 在相同扰动条件下并行对比,用性能退化率量化鲁棒性差异。
1.3. 运行模式
| |
|---|
| 实时演示模式 | 墙钟驱动,物理推进与渲染帧率解耦,长期运行不漂移,支持倍速/慢放切换,GUI 可用 |
| 训练模式 | 忽略墙钟,CPU 全速推进,禁用 GUI,为 RL 策略训练提供最大吞吐 |
| 批处理模式 | 非实时,无 GUI,用于蒙特卡洛仿真、参数扫描与自动化测试 |
2. 背景与动机
2.1. 缘起
在多年前入门飞控时,我时常希望可以遇到一份好的教程。学习过程中购买了网上能找到的大量书籍资料,也为此走了不少弯路。构建此项目的初衷,一方面是整理自己的知识,希望对他人有所帮助;另一方面也是对曾经那个迷茫少年的慰藉——赠与自己一份时光的礼物。
一个业余时间打磨的项目,深度和广度上无法与历经多年迭代的成熟工具相比。如果它能为初学者降低一些门槛,为同行提供一点思路,便已值得。
2.2. 与现有工具的对比
现有开源工具各有侧重,下表从多个维度进行结构化对比,供读者参考和判断:
| | | | | |
|---|
| 语言 | | | | | |
| 开源协议 | | | | | |
| 定位 | | | | | |
| 学习曲线 | | | | | |
| 控制链路透明度 | | | | | |
| RL 集成 | | | | | |
| 气动模型精度 | | | | | |
| 3D 渲染 | | | | | |
| 实时 GUI | | | | | |
| 工程化程度 | | | | | |
本项目的差异化定位在于:轻量、控制链路各环节可独立查看和修改、Python 生态原生集成、RL 训练与传统控制器在统一仿真框架下无缝切换。
3. 技术栈
| | |
|---|
| Python 3.12 / uv / VSCode | 生态丰富,学习资料充足,uv 提供快速且确定性的依赖管理 |
| | NumPy 是 Python 科学计算的事实标准,Numba JIT 可在不离开 Python 的前提下获得接近 C 的性能 |
| | |
| | 类型安全的参数管理,配置即代码,加载阶段即捕获参数错误 |
| | OpenAI Gym 的继任项目,强化学习领域的标准环境接口 |
| | MPC 控制器的非线性规划求解,符号微分免去手动推导 |
| | |
| | |
| | |
| | 现代化文档网站,支持 LaTeX 公式渲染与版本化 |
| | |
选择这些工具并非因为它们是唯一的选择,而是因为它们在社区活跃度、学习资料丰富度和性能之间取得了较好的平衡。如果您的场景需要不同的工具链,模块化的设计应当使得替换成为可能。
4. 系统架构
4.1. 分层结构
系统采用五层架构,自顶向下各层仅依赖其下方的层:
┌─────────────────────────────────────────────────┐│ 可视化与交互层 ││ PySide6 GUI · PyQtGraph · 3D 渲染 │├─────────────────────────────────────────────────┤│ 决策与控制层 ││ 任务规划 · 轨迹规划 · 控制器 · RL 策略推理 │├─────────────────────────────────────────────────┤│ 感知与导航层 ││ 传感器模型 · EKF · UKF · 互补滤波 │├─────────────────────────────────────────────────┤│ 物理仿真层 ││ 动力学 · 执行机构 · 环境扰动 · 大气模型 │├─────────────────────────────────────────────────┤│ 基础设施层 ││ 配置管理 · 工具库 · 坐标变换 · 数据记录 │└─────────────────────────────────────────────────┘
层内模块通过统一接口协议通信。这种依赖方向保证了:更换一个控制器实现不需要触碰动力学代码,更换传感器模型不影响控制逻辑。
4.2. 信号流
以下展示仿真闭环中数据的完整流动路径。理解信号流是理解整个系统的关键——每个功能模块在信号流中的位置决定了它"接收什么、产出什么":
环境条件(风/大气/重力) │ ▼ ┌────────────┐ 实际操纵量 ┌────────────┐ │ 动力学 │◄───────────────│ 执行机构 │◄── 控制指令 │ (6DOF刚体) │ │ (舵机/电机) │ └─────┬──────┘ └────────────┘ │ 真实状态 ▼ ┌────────────┐ 传感器测量 ┌────────────┐ │ 传感器 │───────────────►│ 组合导航 │ │ (IMU/GPS等) │ │ (EKF/UKF) │ └────────────┘ └─────┬──────┘ │ 估计状态 ▼ ┌────────────┐ 阶段指令 ┌────────────┐ │ 任务规划 │───────────────►│ 轨迹规划 │──► 参考轨迹 └────────────┘ └────────────┘ │ ▼ ┌────────────┐ │ 控制器 │──► 控制指令 ──→(回到执行机构) │ (PID/LQR/RL) │ └────────────┘
注意执行机构在信号流中的位置:它处于控制器与动力学之间,将抽象的控制指令(如"油门 70%""舵面偏转 15°")转换为物理上可执行的力和力矩。实际飞行中,舵面不可能瞬时偏转到指令角度,电机也无法瞬间改变转速。建模这些动态特性,使得仿真中的控制响应更接近物理现实。
4.3. 状态定义与通信
所有模块的输入输出基于统一的状态结构体或其切片,避免参数在函数调用中四处散落:
| | |
|---|
state_base | [N, E, D, u, v, w, φ,θ,ψ, p ,q ,r] | |
state_expand | | |
state_sensor | | |
state_wind | [Wn, We, Wd] | |
设计意图:让状态成为模块间唯一的"语言"。每个模块声明自己需要读取哪些字段、写入哪些字段,接口意图一目了然——这比在函数参数列表中传递十几个浮点数要清晰得多,也为后续的并行化和序列化留出明确的接口边界。
4.4. 多速率调度
动力学积分、控制器执行、数据记录各有独立更新周期,彼此保持严格的整数倍关系:
| | | |
|---|
dt_state | | | |
dt_control | | dt_state | |
dt_record | | dt_control | |
由于倍数关系严格,在采样时刻直接取值即可,无需插值或零阶保持处理。这样的设计在实现简单的同时,也便于性能分析——可以清楚地知道每个周期内发生了什么。
4.5. 实时仿真
采用固定时间步长物理推进 + 可变渲染帧率的解耦架构:
- 物理引擎按固定
dt_state 推进,不受渲染性能影响。 - 渲染端通过定时器读取当前仿真状态进行显示,允许丢帧或插值以适应不同硬件条件。
- 长期运行不产生时间漂移(墙钟驱动),可随时切换为非实时、倍速或慢放模式。
为何不让物理引擎同步墙钟? 物理仿真的精度依赖于固定时间步长。如果让物理引擎跟随墙钟运行,在 GUI 渲染负载波动时会导致积分步长不稳定,影响仿真精度。解耦的设计让两者各司其职。
5. 功能模块设计
以下各小节按信号流顺序组织:从外部环境、到物理核心、到感知、到决策、到控制闭环、再到辅助能力。每个模块说明它"是什么"和"为什么这样设计"——前者帮助快速了解功能,后者帮助理解设计意图,也为后续的修改和扩展提供判断依据。
5.1. 坐标系与姿态
坐标系约定:
- 地理坐标系(导航系):北-东-地(NED),右手系
姿态表示:
- 内部计算统一使用四元数(quaternion),避免欧拉角在大姿态角时的万向锁(Gimbal Lock)奇异性——当俯仰角接近 ±90° 时,欧拉角的三个旋转自由度退化为两个,导致数值不稳定。四元数用四个数表示三维旋转,没有这种奇点。
坐标变换的管理策略:
- 动力学方程中禁止直接编写正弦/余弦转换逻辑——这样做不仅容易出错,也不利于代码审查
- 坐标变换函数使用 Numba 修饰,且只接收预先计算好的三角函数值,兼顾可读性与性能
5.2. 配置管理
配置内容:
| |
|---|
| 传统控制器参数、RL 控制器参数(分开配置,避免混杂) |
| |
| |
| 动态特性、噪声特性(按 Allan 方差标准定义) |
| |
| |
| |
设计特性:
- 配置即代码 —— 使用 Python 文件做配置,天然支持版本控制与代码审查,比 YAML/JSON 更灵活
- 类型校验 —— 使用 Pydantic v2,数据类型统一为 NumPy 数组,在加载阶段即捕获参数错误
- 参数摄动 —— 支持对质量、惯量、气动参数、执行机构性能参数、初始状态进行采样扰动,服务于鲁棒性评估和 RL 域随机化
- 内置可视化 —— 配置文件在
if __name__ == "__main__": 下包含绘图入口,方便直接查看参数分布和出图 - 配置版本管理 —— 配置结构随项目迭代可能变化,配置文件头部声明兼容的仿真系统版本,支持旧版本配置的自动迁移
5.2.1. 仿真参数配置
仿真参数使用 Pydantic 模型定义,数据类型为 NumPy 数组。
状态定义:
state_base: [N, E, D, u, v, w, φ, θ, ψ]state_expand(): 扩展状态(角速度、加速度等)
设计原则:所有模块的输入输出均基于上述状态结构体或其切片,避免参数在函数间"满天飞"。这使得模块间的依赖关系显式、可控,也为后续的并行化和序列化留出清晰的接口边界。
5.3. 环境模型
环境模型在每个 dt_state 周期为动力学提供当前时刻的外部条件。它处于信号流的最上游,影响动力学的每一个积分步。
| | |
|---|
| 风扰动 | | |
| 重力场 | | |
| 大气参数 | 空气密度、温度随高度变化(国际标准大气模型 ISA) | |
| 地面效应 | | |
Dryden 湍流模型通过成形滤波器将白噪声转换为具有特定功率谱密度的湍流序列,在工程上被广泛使用。风切变模型描述风速随高度的梯度变化,对进近着陆阶段的飞行安全影响显著。
5.4. 动力学模型
支持机型:
核心设计:
| |
|---|
| 各机型共用六自由度刚体动力学/运动学方程,仅"由输入计算力和力矩"的部分因机型而异 |
| 采用地球曲率坐标系(非平面近似),适用于高空长航时场景 |
| |
| |
| 纯函数实现,参数原地更新(in-place),Numba JIT 加速 |
| 减少重复运算,降低内存分配与 GC 压力;索引常量在模块顶层定义,便于 Numba 编译 |
方程框架概述(供不同背景的读者参考):
对入门读者,"六自由度"指飞行器在三维空间中的三个平移自由度(前后、左右、上下)和三个旋转自由度(滚转、俯仰、偏航),每个自由度都有对应的力或力矩驱动。
核心方程组的结构可概括为:
- 平移动力学:质量 ×(体轴加速度 + 角速度叉乘速度)= 重力 + 气动力 + 推力 + 风扰力
- 旋转动力学:惯性矩阵 × 角加速度 + 角速度叉乘(惯性矩阵 × 角速度)= 气动力矩 + 推力力矩 + 陀螺力矩
- 姿态运动学:四元数的时间导数由体轴角速度和当前四元数共同决定
- 位置运动学:位置的时间导数由方向余弦矩阵将体轴速度转换到地理系得到
方程推导参考 Stevens & Lewis《Aircraft Control and Simulation》第 2 章,或 Etkin《Dynamics of Atmospheric Flight》。理论文档中将以 LaTeX 形式给出完整推导。
为何将力/力矩计算与刚体方程分离? 固定翼的升力来自翼面气动效应,多旋翼的推力来自旋翼——这些物理过程截然不同,但最终都表现为作用在刚体上的力和力矩。将通用的刚体运动学/动力学方程与机型特定的力/力矩计算解耦,新增机型时只需实现力/力矩的计算逻辑,积分器和状态更新代码无需改动。
气动参数的表达方式:实际飞行器的气动系数(升力系数、阻力系数等)通常是攻角、侧滑角、舵面偏角的函数。本项目支持解析模型(多项式拟合)和查找表(多维插值)两种方式,均提供 Numba 加速的实现,用户可根据数据来源和精度需求自行选择。
5.5. 执行机构
建模对象:舵机、电机、电调(ESC)
动力学模型:一阶或二阶线性动力学
非线性特性:
- 舵面间隙 / 死区(Dead Zone)——小指令量不产生响应
- 速率饱和(Rate Saturation)——舵面偏转速率有物理上限
- 位置饱和(Position Saturation)——舵面偏转角度有机械限位
执行机构在信号流中位于控制器与动力学之间。建模这些动态特性的意义在于:控制器的输出是理想指令,而实际到达动力学模型的是经过执行机构"滤波"后的物理操纵量。忽略这一环节,会导致仿真中的响应速度过于乐观。
5.6. 传感器模型
| | |
|---|
| IMU | 零偏(bias)、随机游走(random walk)、高斯白噪声、量程限制 | 惯性导航的核心传感器,也是 EKF/UKF 的主要输入 |
| 气压计 | | |
| GPS | | 全球定位信息,但更新率低(典型 1–10 Hz)且受环境影响 |
| 空速管 | | |
噪声参数按 Allan 方差标准定义。Allan 方差是描述惯性传感器噪声特性的工业标准方法——它是一种时域分析技术,通过在不同平均时间下计算相邻数据段的平均值差异来表征噪声特性。它能够将叠加在一起的不同噪声源(量化噪声、角度随机游走、零偏不稳定性、速率随机游走、速率斜坡)在双对数图上分离成不同斜率的线段。测试中会验证生成的噪声序列是否符合设定的 Allan 方差曲线。
5.7. 组合导航
组合导航将来自不同传感器的测量信息融合,得到比任何单一传感器更准确的状态估计。这是连接"传感器原始数据"与"控制器可用状态"的核心环节。
5.7.1. 滤波算法
| | |
|---|
| EKF 松组合 | 扩展卡尔曼滤波,GPS 位置/速度与 IMU 在导航解算层面融合 | |
| EKF 紧组合 | 扩展卡尔曼滤波,GPS 伪距/伪距率与 IMU 深度融合 | |
| UKF | 无迹卡尔曼滤波,通过 Sigma 点采样逼近非线性变换后的统计特性 | |
| 互补滤波 | 利用频域特性融合高低频传感器(IMU 高频可信、GPS 低频可信) | |
5.7.2. 状态向量与量测模型
以 EKF 为例,典型的状态向量包含:
- 姿态四元数(4 维,协方差传播中使用修正罗德里格斯参数以保持 3 维误差表示)
量测量因组合方式而异:松组合使用 GPS 位置/速度、气压高度;紧组合使用 GPS 伪距/伪距率;空速管为固定翼提供动压量测。
5.7.3. 关键技术考量
| |
|---|
| 可观性 | 并非所有状态都可观——静止时陀螺零偏的可观性很差,需要持续的运动激励才能收敛 |
| 数值稳定性 | 协方差矩阵在长时间运行中可能失去正定性,需采用 Joseph 形式更新或平方根滤波 |
| 四元数一致性 | 滤波器更新后的四元数需要归一化,归一化后的协方差需要相应重映射 |
| 时间对齐 | IMU(高频,如 200 Hz)与 GPS(低频,如 5 Hz)的数据存在时间不对齐问题,需妥善处理 |
5.7.4. 导航性能评估
附加独立的评估模块,提供位置误差、速度误差、姿态误差的统计分析(均值、标准差、RMS、最大值),以及与"真值"的对比可视化。
5.8. 任务规划
管理飞行任务的阶段切换:
起飞 → 爬升 → 巡航 → 末制导 / 着陆
任务规划器根据当前飞行状态(高度、速度、与目标距离等)自动触发阶段迁移。它不直接产生控制指令,而是通知轨迹规划器当前所处阶段,由轨迹规划器生成对应的参考轨迹。
对于固定翼,还可能包括盘旋等待、航线飞行等阶段;对于多旋翼,可能包括悬停、定点降落等阶段。任务规划器的逻辑因机型和任务类型而异,但对外接口保持统一。
5.9. 轨迹规划
| |
|---|
| 基础轨迹 | |
| 平滑轨迹 | Minimum-Snap(最小化四阶导数,产生平滑的四旋翼飞行路径)、B 样条、多项式轨迹 |
| 高度剖面 | |
轨迹规划器输出参考位置、速度、加速度的时间序列,供控制器跟踪。平滑轨迹的价值在于:不连续的参考轨迹会导致控制器输出剧烈跳变,增加执行机构负担并可能激发结构振动。
5.10. 控制器
5.10.1. 控制器列表
| | | |
|---|
| PID | | | |
| LQR | 线性二次调节器,基于线性化模型求解 Riccati 方程 | | |
| MPC | 模型预测控制,基于 CasADi 的非线性滚动优化 | | |
| ADRC | | | |
| 滑模控制 | | | |
| 反步法 | | | |
| RL 策略封装 | | | |
5.10.2. 接口统一
所有控制器实现统一接口(相同的输入输出签名),切换时只需更换配置文件。这种"接口协议化"的设计,使得不同控制器之间的横向对比变得简单直接——在同一仿真条件下,用同一份数据分析代码,就能得到公正的对比结果。
附带控制器参数设计辅助工具:时域分析(阶跃响应、脉冲响应)与频域分析(Bode 图、Nyquist 图),帮助理解系统动态特性并辅助调参。
5.11. 强化学习
5.11.1. 环境配置与参数管理
RL 相关的超参数(学习率、折扣因子、网络结构、训练步数等)独立配置,与传统控制器参数分离,避免配置文件的职责混乱。
5.11.2. 模型/网络创建
封装策略网络(Actor)和价值网络(Critic)的创建逻辑,支持不同网络结构的快速切换。
5.11.3. 训练循环
- 核心训练循环自主实现,便于深入理解每一步的数学原理,也便于调试和魔改
- 预留 Stable-Baselines3 接口,可直接调用社区成熟的 PPO、SAC 等算法
自己造轮子不是目的,而是学习的手段。当理解了训练循环的每一个细节之后,使用成熟框架时才能更好地判断其行为是否符合预期。
5.11.4. 奖励函数
采用可组合的 RewardTerm 结构,每个奖励项独立定义、支持权重配置和归一化:
用户可自行添加新的 RewardTerm,只需实现统一接口。
5.11.5. 域随机化
域随机化(Domain Randomization)是弥合仿真与现实差距的重要技术——通过在训练中随机化物理参数,使策略对模型不确定性具有鲁棒性。
| | |
|---|
reset() | | 质量、惯量、气动参数、执行机构参数、初始状态随机化 |
step() | | |
域随机化不仅服务于 RL 训练,也同时用于传统控制器仿真中的鲁棒性评估——两者共用同一套参数摄动机制。
5.11.6. sim-to-real 迁移
域随机化是 sim-to-real(从仿真到实物)迁移的第一步。完整的迁移链路通常包括:
- 域随机化(本项目已覆盖)——在仿真中随机化参数,扩大策略的适应范围
- 系统辨识(规划中)——用真实飞行数据校准仿真模型参数
- 真实数据微调(规划中)——用少量真实数据对策略进行 fine-tuning
本项目当前主要覆盖第一阶段。第二、三阶段是自然的后续方向,项目的模块化设计为接入真实数据留出了空间。
5.11.7. 向量化并行环境
RL 训练的效率瓶颈通常在仿真吞吐量。Gymnasium 提供了 VectorEnv 接口,支持多个环境实例同时执行 step()。本项目计划支持向量化并行,具体方案包括:
- NumPy 层面的批处理(多个环境的状态合并为矩阵运算)
这对 RL 训练速度的影响是数量级的,值得在设计阶段就纳入考量。
5.12. 仿真环境封装(Gymnasium 接口)
将仿真引擎封装为 Gymnasium 标准环境(继承 gymnasium.Env)。这是一个独立于 RL 模块的通用能力——它定义的是"如何与仿真引擎交互",而非"如何训练策略"。
核心映射:
| |
|---|
reset() | |
step(action) → (observation, reward, terminated, truncated, info) | |
设计意图:
Gymnasium 接口不仅服务于 RL 训练,它同时为传统控制器提供了一套标准化的仿真驱动方式:
- 可以直接使用 Gymnasium 生态中的评估工具(如
check_env 合规性检查) - 仿真可以被任何兼容 Gymnasium 的外部代码驱动,无需了解内部实现细节
- 通过
gymnasium.register() 注册环境后,用户可以用 gym.make("FlightSim-Quadrotor-v0") 的标准方式创建仿真环境
5.13. 数据分析
提供常用性能指标计算与数据处理工具,输出标准化报告(dict / DataFrame)。
| |
|---|
| 时域 | ISE(误差平方积分)、IAE(绝对误差积分)、ITAE(时间加权绝对误差积分)、超调量、调节时间、稳态误差 |
| 姿态 | |
| 跟踪 | |
| 控制 | |
| 鲁棒性 | |
这些指标为控制器之间的定量比较提供了统一的度量标准。数据分析模块同时服务于蒙特卡洛仿真的统计汇总(见 7.8 节)。
5.14. 绘图
| |
|---|
| |
| |
| |
| 基于 PyQtGraph / PyBullet 的实时数据可视化 |
标准输出曲线:
5.15. 工具库
关于坐标变换的归属:所有坐标转换集中在工具库中处理,严禁在动力学方程中直接编写三角函数转换逻辑。集中管理减少出错概率,也便于统一使用 Numba 加速——坐标变换函数只接收预先计算好的三角函数值。
5.16. GUI 交互界面
基于 PySide6 构建,明确区分两种运行模式:
| |
|---|
| 训练模式 | 忽略墙钟,CPU 全速推进,禁用 GUI,最大化训练吞吐 |
| 实时演示模式 | GUI 线程中使用定时器触发渲染,读取当前仿真状态;允许物理引擎跑得比实时快,通过丢帧或插值适应实时显示 |
实时演示模式支持:参数在线调整、仿真暂停 / 继续 / 倍速切换、实时数据曲线显示。
6. 工程实践
6.1. 代码原则与架构哲学
- Pythonic 风格 —— 代码简洁明了、可读性强,善用 Python 特性,追求优雅与高效的平衡
- 组合优于继承 —— 通过组合(has-a)关系构建复杂系统,减少类层级,提高灵活性
- 接口协议化 —— 核心模块(模型、控制器、传感器等)统一接口,新增控制器或传感器只需实现接口协议,改动量尽可能小
- 性能意识 —— 核心运算强制运行在 NumPy/PyTorch 上,变量普遍使用原地更新(in-place)以降低内存分配开销
- Numba 加速策略 —— CPU 密集型函数使用
@numba.njit 加速;索引常量在模块顶层定义以方便 Numba 编译;对于类,在内部方法中调用顶层 Numba 函数实现加速 - 注释与类型 —— 使用中文注释,带类型提示(type hints),风格全局统一
- 可维护与可扩展 —— 新增机型、控制器、传感器时,改动应局限在最小范围内
6.2. 项目目录结构
flight_sim/├── pyproject.toml # 项目元数据与依赖声明(uv 管理)├── uv.lock # 依赖锁定文件├── docs/ # Docusaurus 文档站点源码├── scripts/ # 独立运行脚本(训练、测试、出图)├── src/flight_sim/ # 核心代码库│ ├── configs/ # 配置文件(Python 模块)│ ├── sim/ # 仿真引擎│ ├── dynamics/ # 动力学模型(多旋翼、固定翼,含积分器)│ ├── environment/ # 环境扰动(风、重力、大气)│ ├── sensors/ # 传感器与组合导航│ ├── actuators/ # 执行机构模型│ ├── controllers/ # 控制器库│ ├── rl/ # 强化学习库│ ├── planning/ # 任务规划与轨迹规划│ ├── plotting/ # 绘图与可视化│ ├── analysis/ # 数据分析│ ├── utils/ # 工具库(坐标转换、数学工具)│ └── gui/ # GUI 交互界面└── tests/ ├── unit/ # 单元测试 ├── integration/ # 集成测试 └── regression/ # 回归测试
核心文件在 if __name__ == "__main__": 下包含参数校验与曲线绘制代码,既作为使用示例,也作为快速自检手段。
6.3. 测试体系
6.3.1. 单元测试
6.3.2. 集成测试
| |
|---|
| |
| |
| |
| |
| |
| Gymnasium API 合规性检查(check_env) |
6.3.3. 回归测试
6.3.4. 物理校验清单
6.3.5. 测试工具链
- pytest + pytest-cov:测试执行与覆盖率统计
- hypothesis:基于属性的测试(property-based testing),自动生成边界用例
6.4. 文档
- 理论文档:将动力学方程、EKF/UKF 的状态方程与量测方程、坐标系定义、Dryden 湍流传递函数、LQR 的 Riccati 方程推导、MPC 的优化问题表述、ADRC 的扩张状态观测器、滑模控制的到达条件等内容以 LaTeX 公式完整写入文档。代码告诉你"怎么做",理论文档告诉你"为什么这样做"
- 用户指南:快速开始指南、详细教程、示例代码库、贡献指南
- 贡献指南:明确新增一个控制器/传感器需要实现哪些接口,提供最小模板;定义 PR 代码审查标准(Ruff 通过、mypy 通过、测试覆盖、文档更新)
7. 开发进度
| | | |
|---|
| M1 | | | |
| M2 | | | |
| M3 | 执行机构 + 传感器模型 + Allan 方差验证 | | |
| M3.5 | 组合导航(EKF 松/紧组合、UKF、互补滤波)+ 导航性能评估 | | |
| M4 | | | |
| M4.5 | 控制器 + 导航联合回归测试 | | |
| M5 | | | |
| M6 | Gymnasium 封装 + 奖励函数 + 训练循环 + 域随机化 | | |
| M6.5 | 向量化并行环境 + 批量仿真 + 蒙特卡洛支持 | | |
| M7 | | | |
| M7.5 | 故障注入 + 可复现性保障 + 数据记录与回放 | | |
| M8 | | | |
8. 术语表
飞控领域术语密集,且不同文献的用词习惯可能存在差异。以下列出本文档中使用的主要术语,供快速查阅。
| | |
|---|
| 6-DOF (Six Degrees of Freedom) | |
| | |
| | |
| | 欧拉角在俯仰角接近 ±90° 时失去一个旋转自由度的奇异性 |
| | |
| | |
| | 扩展卡尔曼滤波,通过线性化处理非线性系统的状态估计 |
| | 无迹卡尔曼滤波,通过 Sigma 点采样逼近非线性变换后的统计特性 |
| | |
| | 通过成形滤波器生成具有特定功率谱密度的湍流序列的工程模型 |
| International Standard Atmosphere | |
| Proportional-Integral-Derivative | |
| Linear Quadratic Regulator | |
| | |
| Active Disturbance Rejection Control | |
| | |
| | |
| | |
| Architecture Decision Record | |
| | OpenAI Gym 的继任项目,强化学习的标准环境接口 |
9. 已知限制与未来方向
任何项目都有边界。明确说出当前不做什么,比让读者自行猜测要好,也为后续贡献者提供清晰的扩展方向。
11.1. 当前不支持
11.2. 未来可能的方向
| |
|---|
| |
| |
| |
| |
| 导入 PX4/ArduPilot 飞行日志,与仿真结果对比 |
| |
| |
10. 致谢
项目正在逐步推进中,设计和实现都在持续迭代 (待发布)。如果你在飞控、仿真、控制理论、强化学习或软件工程方面有任何建议,非常欢迎交流。
邮箱:galaxy.destint@hotmail.com
感谢每一位愿意花时间阅读这份文档的人。无论你是刚开始了解飞控的同学,还是在这个领域深耕多年的前辈,抑或是在其他专业有着深厚积累、对飞行控制感到好奇的朋友——你的反馈都是宝贵的。这个项目还在成长中,它需要来自不同视角的声音。
项目当前处于设计与早期实现阶段,设计方案可能在实现过程中根据实际情况调整。本文档最后更新于 2026 年 7 月 31 日。