3. 无人机动力学模型:四旋翼动力学基础、坐标系与欧拉角、推力与力矩模型、在SITL中配置无人机模型参数

各位同学,欢迎来到第三章。前面两章我们聊了SITL是什么,以及怎么把环境搭起来。从这一章开始,我们要真正碰一碰无人机最核心的东西——动力学模型。

说白了,你写的飞控代码好不好,最终要看它能不能让飞机飞稳。而飞机怎么动,完全由动力学模型决定。我当年刚入行时,总觉得动力学是理论派的事,写代码才是硬功夫。结果有一次仿真里飞机疯狂自旋,查了三天才发现是力矩模型里一个符号写反了。嗯,从那以后我再也不敢轻视这章内容了。

本章核心:理解四旋翼的动力学本质,掌握坐标系变换,学会在SITL中配置正确的模型参数。这是后续所有稳定性验证的基础。

3.1 四旋翼动力学基础

四旋翼为什么能飞?四个电机转起来,产生向上的推力,克服重力。但光有推力不够,还得能控制姿态——前后左右、旋转。这就是动力学要解决的问题。

我个人习惯把四旋翼动力学拆成三块来看:

  • 刚体运动学:描述位置、速度、姿态的变化关系,不涉及力。
  • 刚体动力学:力和力矩如何产生加速度和角加速度。
  • 力和力矩模型:电机转速如何转化为推力和力矩。

你看,其实没那么玄乎。飞机在天上飞,跟你在操场上跑是一个道理——你用力蹬地,身体就往前;飞机用桨推空气,飞机就往上。

我的经验:刚开始做仿真时,很多人只关注动力学方程本身,忽略了电机响应延迟。实际上,电机从收到PWM信号到达到目标转速,有几十毫秒的延迟。这个延迟在高频控制中影响很大,我建议你在模型里加上一阶低通滤波来模拟它。

3.2 坐标系与欧拉角

坐标系是动力学里最容易搞混的地方。我见过太多人把机体坐标系和世界坐标系搞反,结果仿真出来的数据完全没法看。

我们主要用两个坐标系:

坐标系 符号 说明
世界坐标系(惯性系) W系 固定在地面,Z轴向上(NED或ENU)
机体坐标系 B系 固定在飞机上,X轴指向机头,Z轴向下

从世界系到机体系的旋转,我们用欧拉角来描述:

  • 偏航角 ψ(Yaw):绕Z轴旋转
  • 俯仰角 θ(Pitch):绕Y轴旋转
  • 横滚角 φ(Roll):绕X轴旋转

旋转顺序我习惯用 Z-Y-X(偏航→俯仰→横滚),这也是PX4和ArduPilot的默认顺序。为什么是这个顺序?因为这样能避免万向锁问题——当然,在仿真里我们通常用四元数来彻底规避它,但理解欧拉角仍然是基础。

注意:欧拉角在俯仰角接近 ±90° 时会出现奇异性。如果你在做特技飞行或全姿态控制,请务必使用四元数。我曾经在项目中因为没注意这个,导致仿真在大角度机动时直接崩溃。

3.3 推力与力矩模型

四旋翼有四个电机,每个电机带动一个螺旋桨。电机转速越快,产生的推力越大。但推力不是唯一的东西——螺旋桨旋转还会产生反扭矩,这就是偏航控制的来源。

单个电机的推力模型很简单:

F_i = k_f * ω_i²

其中 k_f 是推力系数,ω_i 是电机转速。力矩模型类似:

M_i = k_m * ω_i²

但要注意,k_m 的方向取决于螺旋桨的旋转方向。四旋翼通常采用X型布局:

  • 电机1(右前)和电机3(左后):逆时针旋转
  • 电机2(左前)和电机4(右后):顺时针旋转

这样设计的好处是,偏航力矩可以相互抵消一部分,剩下的通过差速控制。

整机的推力和力矩可以写成矩阵形式:

| F_total |   |  k_f   k_f   k_f   k_f   | | ω₁² |
| M_x     | = | -l*k_f l*k_f l*k_f -l*k_f | | ω₂² |
| M_y     |   |  l*k_f l*k_f -l*k_f -l*k_f | | ω₃² |
| M_z     |   |  k_m  -k_m  k_m  -k_m   | | ω₄² |

这里 l 是电机到重心的距离。你看,通过调整四个电机的转速,我们可以独立控制总推力、横滚力矩、俯仰力矩和偏航力矩。

避坑指南:我曾经在配置模型时,把电机布局的符号搞反了。结果飞机在仿真里一推油门就往左偏。检查了半天才发现是力矩矩阵里符号写错了。建议你写完后,用手动测试验证一下:只给一个电机加转速,看飞机的响应是否符合预期。

3.4 在SITL中配置无人机模型参数

好了,理论讲完了,我们来看看在SITL里怎么配。以ArduPilot的SITL为例,模型参数主要在 libraries/SITL/SIM_multicopter.cpp 里定义。

关键参数包括:

参数名 含义 典型值
mass 无人机质量(kg) 1.5
arm_length 电机臂长(m) 0.25
prop_radius 螺旋桨半径(m) 0.127
thrust_coef 推力系数 k_f 1.0e-5
torque_coef 力矩系数 k_m 2.0e-7
drag_coef 空气阻力系数 0.1

修改这些参数后,重新编译SITL即可生效。我个人习惯先不改太多,用默认参数跑一次悬停仿真,看看基本响应是否正常。

# 启动SITL并加载自定义模型
sim_vehicle.py -v ArduCopter --model multicopter --add-param-file=my_params.parm

其中 my_params.parm 里可以覆盖默认参数:

SITL_MASS 1.8
SITL_ARM_LENGTH 0.30
SITL_THRUST_COEF 1.2e-5

重要:参数不是随便改的。比如你把质量改大,推力系数也要相应调整,否则飞机可能飞不起来。我建议你先用理论计算估算一下,再在仿真里微调。另外,空气阻力系数在低速时影响不大,但高速飞行时不能忽略。

3.5 本章知识体系

为了让你更直观地理解本章内容的结构,我画了一张图:

四旋翼动力学模型知识体系 四旋翼动力学模型 刚体运动学 刚体动力学 力与力矩模型 位置/速度关系 欧拉角/四元数 牛顿-欧拉方程 惯性矩阵 推力/力矩矩阵 SITL配置:质量、臂长、推力/力矩系数 电机布局、空气阻力、电机延迟

这张图把本章的知识点串起来了。你看,从顶层的动力学模型出发,分成三个分支,每个分支又有自己的子知识点。最下面是我们实际在SITL里要配置的参数。搞懂了这张图,你就掌握了四旋翼动力学的骨架。