简介:2017年发表于《广西师范大学学报(自然科学版)》的一篇学术论文PDF,聚焦四旋翼无人机的姿态控制问题,面向无人机控制、神经网络/深度学习、数据建模及自动化控制的研究者与学习者。论文针对传统PID控制无法实时更新Kp、Ki、Kd参数,且控制精度不高的问题,提出附加惯性项的BP神经网络与PID相结合的姿态控制方法,并对惯性系数进行修正,以增强无人机在扰动下的飞行稳定性与动态响应能力。仿真实验表明,该方法较BP参数自整定PID控制和传统PID控制,抗扰性、鲁棒性与动态性能均更优,具有较好的工程参考价值。论文还分析了BP神经网络在机器学习与深度学习领域的应用潜力,并附算法流程、参数整定策略及仿真对比曲线,便于读者复现和深入理解。资源包仅含1个PDF文件,容量约338KB,已有190人学习,适合需要快速获取该领域改进思路与算法对比数据的读者。
1. 这篇研究为什么值得看:附加惯性项和BP网络到底解决了什么
调试四旋翼姿态环时,很多人用简化刚体模型先仿真,姿态参数看着都能收敛,一带负载或做大机动,横滚和俯仰就开始互相串扰,调了很久才发现是电机转子高速旋转产生的那一项“小惯性”被忽略了。这篇基于附加惯性项BP神经网络的四旋翼无人机姿态控制研究,要解决的就是两件事:把旋翼转子角动量引起的陀螺力矩作为附加惯性项补进姿态模型,同时用BP神经网络去在线补偿模型里剩余的非线性与扰动。这个方向适合正在做飞控仿真的研究型开发者,也适合想把手上的PID姿态环做得更稳的从业者。下面直接讲模型怎么改、BP网络怎么搭、闭环仿真怎么跑,以及跳过哪一步最容易翻车。
2. 先把姿态模型写对:附加惯性项从哪来,漏掉它会发生什么
对做姿态控制的人来说,第一步统一符号比调参数更值得花时间。常见约定是机体坐标系固连在机身上,原点取重心,x轴指向机头,z轴垂直向下(右手系);导航坐标系取北东地或东北天,仿真里一般用欧拉角表示机身相对导航系的姿态。姿态运动学把欧拉角速度和机体角速度联系起来:
Φ̇ = W(Φ)·ω
其中 W(Φ) 的展开形式为:
[1, sinφ·tanθ, cosφ·tanθ; 0, cosφ, -sinφ; 0, sinφ/cosθ, cosφ/cosθ]这个矩阵在小角度下可以近似成单位阵,但一旦给BP网络做在线补偿,姿态角超过±15°以后,近似误差就变成可观的扰动,仿真模型里建议保留完整形式。下表给出姿态环的状态变量定义,后续所有公式都沿用这套符号。
| 变量 | 含义 | 单位 |
|---|---|---|
| φ, θ, ψ | 滚转、俯仰、偏航欧拉角 | rad |
| p, q, r | 机体角速度分量 | rad/s |
| Jxx, Jyy, Jzz | 机体绕三轴的转动惯量 | kg·m² |
| J_rp | 电机转子加旋翼绕转轴的转动惯量 | kg·m² |
| Ω_i | 第i个旋翼的转速 | rad/s |
| τ_ctrl, τ_dist | 控制力矩、外部扰动力矩 | N·m |
这些状态在仿真模型里直接对应一组积分器。后面控制器、BP网络都是围绕这套状态做文章。
2.1 附加惯性项的具体来源:旋翼转子角动量与陀螺力矩
“附加惯性项”在大多数中文文献里指的不是机体质心偏移,而是电机-旋翼系统绕电机转轴旋转带来的附加角动量。四旋翼的旋翼转速通常在几百到上千rad/s,电机转子和桨盘绕转轴的转动惯量虽然只有机体惯量的百分之一上下,但转速高,角动量 J_rp·Ω 不能当成零。当机体本身在转动(ω不为零)时,这些转子角动量方向随机体一起改变,产生陀螺力矩。
把四个旋翼的角动量合起来,带符号求和:
Ω_sum = Ω1 - Ω2 + Ω3 - Ω4
具体正负号看两个对角旋翼的转向定义。陀螺力矩写成:
τ_gyro = -J_rp · (ω × (Ω_sum·e3))
这里的 e3 是机体z轴单位矢量。把这一项加进刚体动力学,就得到完整姿态动力学方程:
J·ω̇ = -ω×(J·ω) - J_rp·(ω×(Ω_sum·e3)) + τ_ctrl + τ_dist
第一项是刚体本身惯性力矩,第二项就是附加惯性项。注意它不是一个常数,而是机体角速度与旋翼转速的叉积。横滚和俯仰通道在这里天然耦合:想单独滚转,力矩分配出来的结果会被俯仰方向的陀螺力矩拽回去。这个耦合在悬停小幅姿态时看着不明显,旋翼转速差拉大或做大俯仰滚转机动时,会直接限制姿态环带宽。
2.2 漏掉附加惯性项的真实后果:横滚-俯仰耦合与高频抖动
用不含附加惯性项的模型做控制器设计,再用完整模型做仿真验证,差异集中在三个现象上。
第一是耦合串扰:给定滚转阶跃,俯仰角出现同步扰动,跟踪误差曲线产生一个和滚转机动同步的驼峰。第二是带宽受限:把不含陀螺项模型上能用的PID增益搬到完整模型上,系统刚到边界稳定,增大比例增益后最先崩掉的不是目标通道,而是另一个通道。第三是高频抖动:悬停时如果四个旋翼转速差较大,陀螺力矩直接成为持续激励源,姿态角速度噪声明显变大。
三个现象的本质都一样:设计模型漏掉的交叉耦合项被控制器当成了扰动,而线性PID对这种与转速相关的时变扰动补偿能力有限。这也是标题把“附加惯性项”放到BP网络前面的原因——先让机理模型贴近物理系统,再让神经网络去补偿剩余部分,而不是让BP网络从头去学一个包含强耦合的完整黑匣子。下表列一组典型参数量级,仿真时可以直接用。
| 参数 | 常用量级/取值 | 说明 |
|---|---|---|
| Jxx, Jyy | 约1e-2 ~ 2e-2 kg·m² | 结构近似对称,Jxx≈Jyy |
| Jzz | 约2e-2 ~ 3e-2 kg·m² | 偏航惯量通常略大 |
| J_rp | 约1e-5 ~ 1e-4 kg·m² | 电机转子加桨盘,按实物估算 |
| Ω_i | 300 ~ 900 rad/s | 悬停附近转速范围 |
| 控制/采样周期 | 2 ~ 5 ms | 与常见飞控一致 |
提示:J_rp 没有通用值,最可靠的办法是查电机手册的转子惯量,再把桨质量按圆盘近似估算。仿真阶段用量级范围内的值即可,后面会讲这个参数对BP训练影响有多大。
3. BP神经网络在姿态环里的两种用法:结构、输入输出与更新方式
BP神经网络用在姿态控制里,不需要从通用逼近定理开始推导,但至少要把握三点。第一,它是多层前馈网络,信息从输入层经隐藏层到输出层单向传播;第二,训练过程用误差反向传播调整权重,对应到飞控里就是“看到当前误差,计算每个权重该往哪个方向改”;第三,网络本身是一个连续非线性映射,只要输入特征包含足够的状态信息,就能逼近姿态动力学里的残差函数。
常见的bp神经网络结构图可以画成“4×8×3”:输入层4个神经元,隐藏层8个,输出层3个。在姿态环里,输入别直接给原始传感器值,而要给出物理量——误差、误差变化率、积分项、参考角加速度——输出则是PID增益增量或补偿力矩。隐藏层层数,姿态环场景一层就够了;两层隐藏层在实验里没有获得明显收益,反而多出几十个需要调的超参数,训练数据不够时更容易过拟合。
3.1 常规做法是让BP输出PID增量:输入特征与更新率
最常见的做法是把BP网络嵌在PID控制器旁边,输出ΔKp、ΔKi、ΔKd,PID参数按在线增量更新。这样做的好处是飞控主回路维持原有PID结构,即使BP网络出问题,还能退化成固定参数PID继续工作,这是工程上非常值得保留的兜底能力。输入特征一般取:
x = [e, ec, ∫e·dt, φ_d_ref]其中 e 是姿态角误差,ec 是误差变化率,∫e 是带限幅的积分项,φ_d_ref 是期望角加速度(可对期望角速度做差分得到)。最后一个输入不是必须,但如果省略,网络对动态过程的响应会晚半拍。
更新方式有两种。一种是每个控制周期在线更新网络权重,适合工况变化大的场景,缺点是梯度噪声大,必须做梯度裁剪和权重限幅。另一种是离线训练好权重后固定部署,只在飞行途中做前向推理,实时性好、可解释性强,论文和工程都更偏好。我的建议是:先离线训练、固定部署,确认网络输出稳定后再考虑在线更新,顺序不要反。BP网络超参数的初始参考值如下。
| 超参数 | 参考值 | 说明 |
|---|---|---|
| 输入层节点 | 4 | e、ec、∫e、参考角加速度 |
| 隐藏层节点 | 8 ~ 16 | 飞控算力有限时取8 |
| 输出层节点 | 3 | ΔKp、ΔKi、ΔKd 或单个补偿力矩 |
| 隐藏层激活 | tansig | 对称,适合正负误差输入 |
| 输出层激活 | purelin | 让ΔK范围不受压缩 |
| 学习率 | 0.01 ~ 0.05 | 在线更新偏向0.01 |
| 动量系数 | 0.9 | 抑制振荡,加速收敛 |
这些初始值不是玄学,是从误差量级反推的。姿态角误差按弧度计通常不超过0.1量级,学习率太大第一轮迭代就会把权重打飞。
3.2 用BP逼近逆动力学:把附加惯性项当作有界的未知补偿对象
比“BP调整PID参数”更贴合标题的方案,是用BP网络做逆动力学补偿。思路是:姿态动力学里,除了刚体项和附加惯性项,还有气动阻尼、风扰、重心偏移这些没有精确模型的部分。控制器先按机理模型计算理想力矩:
τ_ref = J·a_ref + ω×(J·ω) + J_rp·(ω×(Ω_sum·e3))其中 a_ref 是期望角加速度,由姿态误差换算。没建模的部分交给BP网络逼近,网络输出作为附加力矩叠加到 τ_ref 上。这样BP网络学的是“残差”,而不是整个动力学,学习难度和所需数据量都小一个量级。
训练数据可以从仿真模型采集:给定一组姿态状态,把仿真模型真实需要的补偿力矩和理想公式算出的差值记下来,作为网络标签。数据生成用扫频或随机机动都可以。采用这个结构时,附加惯性项给BP网络提供了一个“基准答案”。如果模型里完全没有这一项,网络输入对应的输出标签里会叠加强耦合成分,网络只能凭统计平均去猜,姿态一变就露馅。把陀螺力矩显式放进公式后,网络只处理气动和扰动残差,泛化能力强很多。这正是这类研究和单纯“用BP做黑匣子控制器”的差别所在。
4. 把方案搭起来:状态方程仿真、bp神经网络python代码训练、闭环验证
仿真模型不需要一开始就上Simulink全套,先用一个MATLAB函数把状态求导写清楚,能大大降低排错成本。以小型四旋翼悬停附近为例,核心求解代码如下。
function xd = attitude_dyn(x, tau, Omega_sum, param) % x = [phi; theta; psi; p; q; r] % tau = [tau_x; tau_y; tau_z] 控制力矩 % param 包含 Jxx, Jyy, Jzz, Jrp phi = x(1); theta = x(2); psi = x(3); p = x(4); q = x(5); r = x(6); w = [p; q; r]; J = diag([param.Jxx, param.Jyy, param.Jzz]); % 刚体惯性力矩 + 附加惯性项(旋翼陀螺力矩) h_gyro = param.Jrp * Omega_sum * [0; 0; 1]; wd = J \ (tau - cross(w, J*w) - cross(w, h_gyro)); % 完整欧拉角运动学,不取小角度近似 Phi = [1, sin(phi)*tan(theta), cos(phi)*tan(theta); 0, cos(phi), -sin(phi); 0, sin(phi)/cos(theta), cos(phi)/cos(theta)]; phid = Phi * w; xd = [phid; wd]; end这一段对应前面2.2节的完整动力学方程。J 是机体转动惯量对角阵;h_gyro 是四个旋翼合成转子角动量;cross(w,J*w) 是刚体陀螺项;cross(w,h_gyro) 就是附加惯性项的陀螺力矩;最后运动学部分保留完整 W 矩阵,不是小角度近似,避免BP网络在较大姿态角下学到错误映射。参数建议按表2的量级初设,用固定步长求解器(步长1ms)先跑通开环,再闭合控制。
注意:在Simulink里对应S函数或积分器组,状态初值别设全零,给一个5°的初始姿态偏差,方便后面看收敛曲线。
4.1 用bp神经网络python代码训练残差补偿网络
训练数据这样生成:在上一节的仿真模型里,让姿态角在±20°范围内做随机机动,记录每个控制周期的姿态角、角速度、角加速度,以及“实际模型所需力矩”和“机理公式计算力矩”的差值。这个差值就是BP网络的标签。数据存成CSV,特征和标签分列。训练代码用纯numpy实现三层BP网络,避免依赖过重的框架,也方便把权重导出到飞控。
import numpy as np def load_data(path): # CSV列依次为: phi,theta,psi,p,q,r, tau_residual_x,tau_residual_y,tau_residual_z data = np.loadtxt(path, delimiter=',', skiprows=1) X = data[:, :6] # 当前姿态状态 y = data[:, -3:] # 残差力矩 return X, y def normalize(X, mu, sigma): return (X - mu) / (sigma + 1e-8) # 网络结构:6输入-12隐藏-3输出 np.random.seed(0) n_in, n_hidden, n_out = 6, 12, 3 W1 = np.random.randn(n_in, n_hidden) * 0.1 b1 = np.zeros((1, n_hidden)) W2 = np.random.randn(n_hidden, n_out) * 0.1 b2 = np.zeros((1, n_out)) def forward(X): z1 = X @ W1 + b1 a1 = np.tanh(z1) # 隐藏层用tanh,输出不会饱和 z2 = a1 @ W2 + b2 return z2, a1 def train(X, y, lr=0.02, epochs=500, batch=64): mu, sigma = X.mean(0), X.std(0) X = normalize(X, mu, sigma) for epoch in range(epochs): idx = np.random.permutation(len(X)) for i in range(0, len(X), batch): bx = X[idx[i:i+batch]] by = y[idx[i:i+batch]] out, a1 = forward(bx) d2 = (out - by) / batch dW2 = a1.T @ d2 db2 = d2.sum(0, keepdims=True) d1 = d2 @ W2.T * (1 - a1 ** 2) dW1 = bx.T @ d1 db1 = d1.sum(0, keepdims=True) W1 -= lr * dW1; b1 -= lr * db1 W2 -= lr * dW2; b2 -= lr * db2 if epoch % 100 == 0: pred, _ = forward(normalize(X, mu, sigma)) print(f"epoch {epoch}, mse {np.mean((pred - y) ** 2):.6f}") return mu, sigma这个实现里关键参数是学习率0.02、批大小64、隐藏层12个节点、tanh激活。残差力矩的量级很小(10^-2 N·m),输出层直接用线性,避免激活函数把输出压到0附近;隐藏层用tanh是因为误差有正有负,tanh对称且在中间区导数变化平缓,比ReLU更适合力矩补偿这类连续回归任务。训练结束后把 W1、b1、W2、b2 连同 mu、sigma 导出成头文件或二进制,供Simulink或飞控加载。注意这里只做了标准化没做归一化,姿态角、角速度、力矩量纲不同,标准化把各列压到零均值单位方差,网络输入各维才是同等尺度。
4.2 闭环验证参数:采样周期、学习率、力矩限幅
网络部署回仿真模型,推荐参数如下。
| 参数 | 取值 | 说明 |
|---|---|---|
| 控制/采样周期 | 2 ms | 与常见飞控一致 |
| 姿态环PID | Kp=120,Ki=8,Kd=18(参考值) | 先单独跑PID,确认稳定再叠加BP |
| BP前向推理周期 | 2 ms | 每个控制周期都算一次 |
| BP输出限幅 | ±0.05 N·m | 残差补偿不允许覆盖主控制量 |
| 训练数据规模 | 4万~8万样本 | 覆盖±20°随机机动 |
| 初始姿态偏差 | 5°~10° | 用于看收敛过程 |
闭环验证按三个步骤进行。第一步只跑PID,记录阶跃响应的超调、调节时间、稳态误差;第二步打开BP补偿,对比同样工况的曲线;第三步在力矩输入处注入持续扰动(正弦或阵风模型),看稳态误差有没有被BP压下来。判断标准:超调小于15%、调节时间小于1s、加入扰动后的稳态误差比纯PID下降30%以上。三条都满足,再谈移植真机。
5. 必踩的五个坑:训练数据、惯性参数、激活函数与验证方法
从仿真到真机,血泪经验基本集中在下面五条。每一条都按现象、原因、解决的顺序写,方便对号入座。
5.1 现象:训练一切正常,一接进闭环模型就高频抖动
原因:训练数据里没有覆盖控制器输出饱和的情况。BP网络在力矩接近限幅时学习到的映射和线性区完全不同,闭环里一旦PID输出饱和,网络给出的补偿力矩又叠加在饱和值上,形成振荡。
解决:训练时把控制力矩限幅作为数据生成条件,超过限幅的样本要么丢弃要么打上饱和标记;网络输出再额外做一次限幅,推荐限幅设为主控制力矩的20%以内。
5.2 现象:滚转角收敛挺好,俯仰角出现周期性摆动
原因:J_rp参数设置偏差过大,模型里陀螺力矩方向和实际不符。BP网络补偿了部分耦合,但摆动周期对应旋翼转速差变化的周期,频率比姿态运动高很多,网络学到的只是平均效果。
解决:先把J_rp的量级校准。让仿真模型悬停,给一个滚转阶跃,记录俯仰耦合的幅值和相位,反过来用陀螺力矩公式反算J_rp,再把反算值代入模型重新生成训练数据。这一步做扎实后,后面很多“莫名奇异”的现象会一起消失。
5.3 现象:隐藏层用ReLU,网络输出在姿态角过零时出现死区
原因:ReLU对负输入直接输出0,而姿态通道误差正负交替,部分神经元权重更新后落入负区间就不再参与学习,整个网络输出产生死区。表现就是姿态角过零附近补偿力矩突然消失,曲线出现一个“平台”。
解决:回归类任务不要用ReLU,隐藏层换tanh或sigmoid,输出层保持线性。如果必须用ReLU,至少加LeakyReLU且leak系数不小于0.01。姿态控制是连续回归问题,选择激活函数时优先考虑对称性和导数连续性。
5.4 现象:仿真指标很好看,一移植到飞控就翻车
原因:训练和验证用了同一批数据,或验证数据里混入了训练样本。BP网络记住了数据而不是学到残差规律,真机飞行时的噪声、时延和仿真完全不匹配,一换工况就暴露。
解决:数据按时间顺序切分成训练、验证、测试三份。不能随机切分,否则相邻样本高度相关,验证结果会“看起来”更好;测试集必须用一段完全没参与训练的机动轨迹。网络隐藏层尽量小,能拟合训练集就够,不要在训练集上追求极小的MSE,那基本是过拟合的信号。
5.5 现象:网络推理加入后,飞控CPU占用飙升,控制周期不稳定
原因:在线更新权重或前向推理放在中断里执行,矩阵运算耗时超过控制周期;角度更新滞后,让网络输入和实际状态差了多个采样周期。
解决:固定部署时把网络推理拆到主循环,权重更新只在空闲时做;输入信号先做一阶低通滤波再给网络,时间常数取2~3个采样周期。这一步常被当成“玄学”,其实是采样和执行时序不对齐导致的相位滞后,滤波后网络稳定性能明显提升。
6. 更省事的验证捷径:先加扰动通道,再谈真机
如果暂时不想把J_rp标定得很准,可以换一个验证思路:在Simulink模型(或你的飞控仿真环境)的姿态力矩总和点加一个扰动信号,扰动形式和陀螺力矩接近——频率与旋翼转速相关、幅值随角速度变化。这样在没有真实硬件的条件下,也能检验BP网络是否具备对抗这类耦合的能力。具体做法:在τ_dist通道注入:
d = A·sin(2π·f·t)·[1; 1; 0.5]A从0.02 N·m起步,f取悬停旋翼转速对应的基频量级,观察BP开启前后的跟踪误差变化。如果BP开启后误差明显回落,说明网络学到的是有效残差模型;如果误差反而变大,先别急着调网络,回去检查耦合的方向符号是不是反了。
三个判定指标能帮你快速决定“值不值得继续投入”:姿态角超调小于15%,调节时间小于1s(阶跃5°到10°),BP补偿后稳态误差降幅不低于30%。三条都满足再上真机。如果达不到,先不要怀疑BP网络,回到4.1节的模型——多半是附加惯性项符号定义反了,或者训练标签里包含了饱和样本。
这个方向本身是值得做的:机理模型补偿主耦合,神经网络拟合残差,正好互补。但它的收益上限取决于前两步建模和训练数据的质量。这套流程我每次都先跑“纯PID→加扰动→开BP”三步,已经成了习惯。养成这个习惯前后,踩坑率差很多,希望帮到你。
本文还有配套的精品资源,点击获取