4、定高模式控制逻辑:目标高度锁定机制、PID控制器设计(串级PID:外环位置/内环速度)、积分限幅与抗饱和

各位同学,今天我们来啃一块硬骨头——定高模式的核心控制逻辑。说实话,很多飞控新手甚至老手,都在这个地方栽过跟头。我自己刚入行那会儿,调出来的定高要么像坐电梯一样忽上忽下,要么干脆直接炸机。嗯,今天我就把当年踩过的坑,连同这些年积累的经验,一次性讲透。

4.1 目标高度锁定机制:别让无人机“忘了”该飞多高

先问大家一个问题:当你把油门推到某个位置,无人机悬停住了,这时候你松手,它应该干嘛?

对,保持当前高度。但问题是——它怎么知道“当前高度”是多少?

这里就要引入目标高度锁定机制。说白了,就是当飞控进入定高模式的那一刻,系统会立刻把当前的气压计读数“拍个照”,存下来作为目标高度。

核心逻辑:

  • 进入定高模式瞬间 → 记录当前高度为 target_altitude
  • 后续控制 → 让实际高度 current_altitude 始终逼近 target_altitude
  • 如果用户通过摇杆给出高度修正指令 → 更新 target_altitude

我个人习惯在代码里用一个全局变量来存这个目标值。每次进入定高模式,先强制更新一次。为什么?因为我在项目里遇到过,无人机从自稳模式切到定高模式时,如果目标高度没及时更新,飞机会猛地窜一下——那感觉,就像有人从背后推了你一把。

避坑指南:我曾经在切换模式时忘记重置目标高度,结果无人机以为它还在10米高空,实际已经在2米了。你猜怎么着?它直接满油门往上冲。所以,切换模式时务必重新锁定目标高度。

4.2 串级PID设计:外环位置,内环速度

好,目标高度有了,接下来怎么控制?很多新手会直接用一个PID,把高度误差映射成油门输出。结果呢?震荡、超调、甚至掉高。

为什么?因为高度控制本质上是个二阶系统。你想想看,油门改变的是加速度,加速度积分得到速度,速度再积分才得到位置。单环PID根本hold不住这种双重积分特性。

所以,业界主流方案是串级PID

  • 外环(位置环):输入是高度误差,输出是期望速度
  • 内环(速度环):输入是期望速度与实际速度的误差,输出是油门/推力

我画了一张图,帮你理解这个结构:

串级PID控制结构图(定高模式) 目标高度 外环PID (位置→速度) 内环PID (速度→油门) 电机/桨 实际高度反馈 实际速度反馈

看到没?外环输出的是期望速度,内环再去跟踪这个速度。这样做的好处是:外环只管位置误差,内环只管速度跟踪,各司其职。

4.3 积分限幅与抗饱和:别让积分“积”出问题

讲完串级结构,咱们聊聊积分。PID里的I项,说白了就是“算旧账”——把过去的误差累积起来。但问题来了:如果无人机一直被外力压着飞不上去,积分项会一直累加,越积越大。

等外力突然消失,积分项释放出来的能量,足以让无人机像火箭一样窜出去。这就是积分饱和

警告:积分饱和是定高模式炸机的头号元凶之一。我见过太多案例,无人机被风吹低了,积分疯狂累加,风停后直接冲上20米高空然后翻倒。所以,积分限幅不是可选项,是必选项。

怎么解决?两个手段:

  1. 积分限幅:给积分项设置一个上限。比如油门输出范围是1000~2000,那积分项最大贡献别超过200。
  2. 抗饱和(Anti-windup):当控制器输出达到执行器极限时,停止积分累加。说白了就是“既然油门已经推到顶了,再积分也没用,先停一停”。

代码实现其实不复杂,我贴一段核心逻辑:

// 外环PID(位置→速度)
float pos_error = target_altitude - current_altitude;
pos_integral += pos_error * dt;

// 积分限幅
if (pos_integral > POS_INTEGRAL_LIMIT) pos_integral = POS_INTEGRAL_LIMIT;
if (pos_integral < -POS_INTEGRAL_LIMIT) pos_integral = -POS_INTEGRAL_LIMIT;

float target_velocity = pos_kp * pos_error + pos_ki * pos_integral + pos_kd * (pos_error - last_pos_error) / dt;

// 内环PID(速度→油门)
float vel_error = target_velocity - current_velocity;
vel_integral += vel_error * dt;

// 抗饱和:如果油门已经饱和,停止积分
if (throttle_output >= THROTTLE_MAX || throttle_output <= THROTTLE_MIN) {
    vel_integral -= vel_error * dt;  // 回退本次积分
}

// 积分限幅
if (vel_integral > VEL_INTEGRAL_LIMIT) vel_integral = VEL_INTEGRAL_LIMIT;
if (vel_integral < -VEL_INTEGRAL_LIMIT) vel_integral = -VEL_INTEGRAL_LIMIT;

float throttle_output = vel_kp * vel_error + vel_ki * vel_integral + vel_kd * (vel_error - last_vel_error) / dt;

个人经验:我习惯把积分限幅设成总输出范围的10%~20%。比如油门范围是1000~2000,那积分限幅就设在±100左右。太小了补偿不够,太大了容易饱和。这个值需要根据实际机型微调。

4.4 调参顺序:先内环,后外环

最后说下调参顺序。很多同学一上来就调外环的P,结果发现怎么调都震荡。为什么?因为内环还没调好,外环看到的“速度响应”是乱的。

我的调参顺序是:

步骤 操作 说明
1 调内环P 让速度响应快速、无震荡。用手推无人机,感觉阻力适中
2 调内环I 消除稳态速度误差。注意积分限幅别太大
3 调内环D 抑制超调。D太大会引入噪声,适可而止
4 调外环P 让高度响应灵敏。P太大→震荡,P太小→反应慢
5 调外环I 消除高度静差。同样注意限幅
6 整体微调 结合飞行数据,微调所有参数

嗯,这套流程我用了快十年,基本没翻过车。你照着来,至少能保证无人机不抽风。

好了,今天的内容就到这儿。定高模式的核心就是:锁住目标、串级控制、管好积分。下一节我们会聊气压计数据的滤波与融合,那又是另一门学问了。


公众号:蓝海资料掘金营,微信deep3321