4. 动力学建模:牛顿-欧拉方程、刚体运动学、空气动力学、电机与螺旋桨模型
好,咱们进入正题。这一章是四轴飞行器控制的理论基石——动力学建模。说白了,就是搞清楚飞机为什么会飞,以及怎么用数学描述它的运动。
我个人习惯把建模分成四块:刚体运动学、牛顿-欧拉方程、空气动力学、电机与螺旋桨模型。每一块都踩过坑,咱们慢慢聊。
4.1 刚体运动学:位置、速度与姿态
先讲运动学。运动学只描述运动,不管力。你想想看,飞机在天上飞,它的位置、速度、加速度怎么表示?
我们通常用两个坐标系:地球坐标系(惯性系)和机体坐标系。地球坐标系固定在地面,机体坐标系跟着飞机转。
位置和速度很简单,就是在地球坐标系下的三个分量:x, y, z 和 vx, vy, vz。但姿态就有点绕了。
描述姿态,我建议用四元数。为什么?因为欧拉角有万向锁问题,我在项目中吃过这个亏。有一次调试悬停,飞机突然乱转,查了半天发现是欧拉角在俯仰90度时奇异性导致的。从那以后,我全部改用四元数。
四元数 q = [q0, q1, q2, q3]^T,满足 q0^2 + q1^2 + q2^2 + q3^2 = 1。它的更新方程是:
dq/dt = 0.5 * q ⊗ ω
其中 ω 是机体角速度,⊗ 表示四元数乘法。这个方程在代码里实现很简单,但要注意归一化——我见过有人忘了归一化,积分几次后四元数就飘了。
4.2 牛顿-欧拉方程:力与力矩
运动学讲完了,该讲动力学了。动力学研究力和运动的关系。四轴飞行器是刚体,所以用牛顿-欧拉方程。
牛顿方程(平动):
m * dv/dt = F_gravity + F_thrust + F_drag
m 是质量,v 是速度。F_gravity 是重力,F_thrust 是四个电机产生的总推力,F_drag 是空气阻力。
欧拉方程(转动):
J * dω/dt = τ - ω × (J * ω)
J 是惯性矩阵,ω 是角速度,τ 是外力矩。注意那个叉乘项 ω × (J * ω),这是陀螺效应。我刚开始做控制时忽略了这一项,结果高速旋转时飞机抖得厉害。
嗯,这里要注意:惯性矩阵 J 是对角阵吗?理论上,如果飞机完全对称,J 是对角阵。但实际中,电池、摄像头等负载会导致不对称。我建议在建模时保留非对角项,虽然计算复杂点,但更准确。
核心公式总结:
- 平动:m * a = F_total
- 转动:J * α = τ_total - ω × (J * ω)
4.3 空气动力学:阻力与升力
空气动力学是四轴飞行器建模里最玄学的部分。为什么?因为空气流动太复杂了,很难精确建模。
我们通常用简化模型:
- 升力:每个螺旋桨产生的升力与转速平方成正比。F_i = k_f * ω_i^2
- 阻力:平动时受到的空气阻力与速度平方成正比。F_drag = 0.5 * ρ * C_d * A * v^2
- 反扭矩:螺旋桨旋转时产生的反扭矩。τ_i = k_m * ω_i^2
k_f 和 k_m 是螺旋桨的力系数和力矩系数,需要通过实验标定。我记得第一次做标定时,用拉力计测数据,发现 k_f 在不同转速下不是常数——因为螺旋桨在高速时效率会下降。
所以,我建议在建模时把 k_f 和 k_m 做成转速的函数,而不是常数。虽然麻烦点,但精度提升明显。
4.4 电机与螺旋桨模型
电机和螺旋桨是执行机构,把控制信号变成力和力矩。常用的电机是无刷直流电机(BLDC),配合电子调速器(ESC)。
电机模型通常用一阶惯性环节:
dω/dt = (1/τ_m) * (ω_cmd - ω)
τ_m 是电机时间常数,ω_cmd 是期望转速,ω 是实际转速。这个模型很简单,但够用。
螺旋桨模型就是前面说的:
F = k_f * ω^2
τ = k_m * ω^2
注意,四个螺旋桨的旋转方向是交替的:两个顺时针,两个逆时针。这样做的目的是抵消反扭矩,让飞机不会自旋。
我建议在代码里这样组织电机模型:
// 电机模型
typedef struct {
float omega; // 当前转速
float omega_cmd; // 期望转速
float tau_m; // 时间常数
float kf; // 力系数
float km; // 力矩系数
} MotorModel;
void motor_update(MotorModel *motor, float dt) {
// 一阶惯性
motor->omega += (motor->omega_cmd - motor->omega) / motor->tau_m * dt;
// 限幅
if (motor->omega < 0) motor->omega = 0;
if (motor->omega > MAX_OMEGA) motor->omega = MAX_OMEGA;
}
这个代码我用了很多年,简单可靠。但要注意,实际电机的响应比一阶模型复杂,有延迟、有非线性。如果做高精度控制,建议用更精细的模型。
4.5 完整动力学方程
把上面所有东西拼起来,就是完整的动力学方程:
// 状态量:位置、速度、姿态(四元数)、角速度
// 输入量:四个电机的转速指令
// 1. 电机模型:计算实际转速
for (i = 0; i < 4; i++) {
motor_update(&motor[i], dt);
}
// 2. 力和力矩计算
F_total = [0, 0, -m*g] + sum(F_i) + F_drag;
tau_total = sum(tau_i) + tau_gyro;
// 3. 牛顿方程:更新速度
dv = F_total / m * dt;
// 4. 欧拉方程:更新角速度
domega = J_inv * (tau_total - omega × (J * omega)) * dt;
// 5. 运动学:更新位置和姿态
pos += vel * dt;
q += 0.5 * q ⊗ omega * dt;
q = normalize(q);
这个流程就是四轴飞行器仿真的核心。我在做飞控算法验证时,都是先跑这个模型,再上真机。为什么?因为真机炸一次成本太高,仿真里随便炸。
重要提醒:仿真模型再精确,也和真实飞行有差距。我建议在仿真中故意加入一些噪声和不确定性,比如传感器噪声、电机延迟、重心偏移等。这样仿真出来的结果才更有参考价值。
4.6 参数辨识
模型建好了,参数怎么来?靠猜肯定不行。我常用的方法:
- 质量 m:直接称重
- 惯性矩阵 J:用 CAD 软件估算,或者做摆锤实验
- 力系数 k_f、力矩系数 k_m:用拉力台标定
- 电机时间常数 τ_m:测阶跃响应,拟合一阶模型
- 阻力系数 C_d:风洞实验,或者飞行数据反推
说实话,参数辨识是最枯燥但最重要的一步。我见过有人直接拿别人的参数用,结果飞机飞起来像喝醉了酒。每个飞机的参数都不一样,必须自己测。
4.7 小结
这一章内容不少,但核心就几句话:
- 运动学描述位置和姿态的变化
- 动力学描述力和运动的关系
- 空气动力学简化了升力和阻力
- 电机和螺旋桨把控制信号变成力
把这些模型写进代码,你就有了一个四轴飞行器的仿真器。下一章,我们会在这个模型基础上设计控制器。嗯,到时候你会发现,模型越精确,控制器越好调。
好了,这一章就到这。有什么问题,咱们下一章见。