3. 航点数据结构:把飞行指令翻译成机器能懂的语言

做航点规划,说白了就是给无人机写一份「飞行剧本」。但无人机不像人,它听不懂「飞到那个山头拍张照」这种话。你得把每个动作拆成结构化的数据——这就是航点数据结构存在的意义。

我个人习惯把航点比作「路书上的一个站点」。每个站点不光有位置,还有到了之后要干什么、怎么干。今天我们就来拆开这个结构,看看里面到底装了些什么。

3.1 航点结构体定义:最基本的积木块

不管用哪个厂商的SDK,航点结构体的骨架都差不多。我拿一个典型的定义来举例:

typedef struct {
    double      latitude;       // 纬度,单位度
    double      longitude;      // 经度,单位度
    float       altitude;       // 海拔高度,单位米
    float       heading;        // 航向角,单位度,0=正北
    uint16_t    stay_time;      // 停留时间,单位秒
    uint8_t     action_count;   // 动作数量
    Action      actions[8];     // 动作列表,最多8个
    uint8_t     speed;          // 到达该点的速度百分比
    uint8_t    转弯模式;        // 0=直线,1=曲线
} Waypoint;

嗯,这里要注意:转弯模式这个字段,不同厂家叫法不一样。大疆叫「转弯模式」,Pixhawk系统里叫「转弯半径」。但本质都一样——控制飞机怎么从一个点过渡到下一个点。

核心要点:航点结构体是「位置 + 行为 + 控制参数」的三元组。缺了任何一个,任务执行都可能出问题。

3.2 航点属性:经纬度、海拔、航向角、停留时间

这四个属性是航点的「身份证」。咱们一个一个说。

3.2.1 经纬度(Latitude / Longitude)

这个不用多解释,地球上的坐标。但有个坑——精度问题。我曾经在项目里用float存经纬度,结果飞到几百米外才发现位置偏了。为什么?float只有7位有效数字,经纬度的小数点后第6位代表约0.1米的误差。你想想看,累积几个点之后,航线就歪了。

我的建议:经纬度一律用double,别省那4个字节。

3.2.2 海拔高度(Altitude)

这里有个容易混淆的概念:相对高度 vs 绝对高度。

类型 参考基准 典型场景 注意事项
相对高度 起飞点 低空巡检、贴近拍摄 起飞点变化,航线就废了
绝对高度 海平面(MSL) 测绘、跨区域飞行 需要高精度DEM数据
气压高度 标准气压面 应急备份 受天气影响大,误差可达几十米

我个人习惯在航点结构体里加一个altitude_type字段,明确告诉飞控用哪个基准。不然你在地面站看到的高度和飞机实际飞的高度,可能根本不是一回事。

3.2.3 航向角(Heading)

航向角决定了飞机机头指向哪里。0度是正北,顺时针增加。但这里有个细节——航向角 ≠ 飞行方向。

举个例子:飞机从A点飞向B点,飞行方向是90度(正东)。但如果你想让相机始终对准北边的目标,航向角就得设成0度。说白了,航向角控制的是「脸朝哪」,不是「往哪走」。

小技巧:在测绘任务中,我通常把航向角设成与航线方向垂直。这样相机扫过的覆盖范围最大,重叠率也最均匀。

3.2.4 停留时间(Stay Time)

这个字段看似简单,但用不好会出大问题。我曾经见过一个新手,把每个航点的停留时间都设成10秒。结果一条50个点的航线,光悬停就花了8分钟,电池全耗在等待上了。

什么时候该设停留时间?

  • 拍照任务:等飞机稳定后再拍,一般2-3秒足够
  • 变焦或对焦:相机需要时间调整,5-8秒比较稳妥
  • 云台调整:如果云台要转大角度,留3-5秒
  • 纯过点:停留时间设为0,飞机直接飞过不停留

3.3 航点动作:让无人机不只是飞过去

光有位置属性,飞机只能做「空中公交车」。真正让航点任务有价值的,是动作系统。

3.3.1 拍照动作

最常见的动作,没有之一。但拍照也分好几种:

typedef enum {
    ACTION_SINGLE_SHOT,     // 单拍
    ACTION_BURST_SHOT,      // 连拍(3/5/7张)
    ACTION_AEB,             // 包围曝光
    ACTION_INTERVAL,        // 定时拍(配合航线速度)
    ACTION_HDR,             // HDR合成
} PhotoAction;

我个人最常用的是单拍 + 定时拍的组合。单拍用于关键点位(比如塔顶),定时拍用于航线中间的连续覆盖。你想想看,如果每个点都单拍,航线速度会被频繁打断,效率很低。

3.3.2 变焦动作

变焦是巡检任务的刚需。但变焦动作有个坑——变焦速度。我曾经在项目里直接设了一个目标焦距,结果相机「唰」一下变过去,画面剧烈抖动,拍出来的照片全是糊的。

正确的做法:把变焦拆成多个步骤,每个步骤只变一点点。比如从24mm变到120mm,可以拆成24→35→50→70→120,每步之间留1秒稳定时间。

警告:变焦过程中不要同时触发拍照。相机的ISP(图像信号处理器)在变焦时负载很高,这时候拍照容易丢帧或出现坏点。先变焦,等稳定了再拍。

3.3.3 云台控制

云台控制是航点动作里最灵活,也最容易出错的。控制参数通常包括:

参数 范围 说明
pitch(俯仰) -90° ~ +30° 负值向下,正值向上
yaw(偏航) -180° ~ +180° 相对机头或绝对角度
roll(横滚) -45° ~ +45° 大部分任务用不到
speed(速度) 1 ~ 100 云台转动速度百分比
mode(模式) 0/1 0=绝对角度,1=相对角度

这里有个容易忽略的点:云台偏航和飞机航向角的关系。如果你设了云台偏航为绝对角度30度,但飞机航向角也在变,云台会一直「追」那个绝对方向。结果就是云台电机一直在微调,画面反而晃来晃去。

我的经验:除非有特殊需求,否则云台偏航用相对模式,跟着机头走。这样飞机转弯时,云台和机身的相对关系不变,画面最稳定。

3.4 航点数据结构总览图

下面这张图把整个航点数据结构的层次关系画清楚了。你可以把它当作「航点任务的数据字典」来用。

航点数据结构层次图 航点数据结构层次图 航点 (Waypoint) 位置属性 控制参数 动作列表 纬度 经度 海拔 double double float 航向角 速度 转弯模式 float uint8 uint8 拍照 变焦 云台控制 枚举 uint16 结构体 核心设计原则 每个航点 = 位置属性 + 控制参数 + 动作列表,三者缺一不可 动作列表支持最多8个动作,按顺序执行。每个动作可独立配置参数。 数据流向:地面站 → 航点列表 → 飞控解析 → 执行器(电机/云台/相机) 任务执行

3.5 实战中的避坑指南

最后,分享几个我在项目中踩过的坑,希望能帮你少走弯路。

坑1:经纬度精度丢失

我曾经用float存经纬度,结果在1000米外的航点偏差了2米。排查了一天才发现是数据类型的问题。从此以后,所有经纬度一律用double。

坑2:海拔基准不统一

有一次在山区做测绘,地面站显示高度50米,但飞机实际离地只有30米。后来发现地面站用的是相对高度(以起飞点为基准),而飞控用的是绝对高度(以海平面为基准)。两者差了20米,因为起飞点本身海拔就有20米。

坑3:动作执行顺序

航点动作是按顺序执行的。如果你先变焦再拍照,没问题。但如果你先拍照再变焦,拍到的照片就是变焦前的画面。这个逻辑看起来简单,但我在项目里见过有人把顺序搞反,结果拍了一堆模糊的照片。

嗯,航点数据结构就讲到这里。说白了,它就是一份「飞行 + 拍摄」的详细说明书。把每个字段理解透,你的航点任务就成功了一半。