3. 航点数据结构:坐标、动作与参数

航点,说白了就是无人机在天空中要踩的一个个「脚印」。但光有位置还不够——飞机到了那个点要干什么?飞多快?停多久?这些信息都得打包进一个数据结构里。

我最早接触航点数据时,用的是大疆的 Waypoint Mission 格式。那时候踩过不少坑,比如动作参数写错了,飞机在航点上空转圈就是不降落。嗯,今天咱们就把这个数据结构彻底拆开讲清楚。

3.1 航点坐标:经纬度与海拔

每个航点最核心的信息就是位置。通常用三个值表示:

  • 纬度(Latitude):范围 -90° 到 +90°,北正南负
  • 经度(Longitude):范围 -180° 到 +180°,东正西负
  • 海拔(Altitude):单位米,通常指相对起飞点的高度(相对高)或 WGS84 椭球高(绝对高)

关键点:海拔类型一定要提前约定。我见过一个项目,飞控用相对高,地面站用绝对高,结果飞机在山区直接撞山。血的教训。

坐标精度方面,一般保留 6-7 位小数就够了。再多也没意义,因为民用 GPS 的精度也就那样。

// 一个典型的航点坐标结构
{
  "latitude": 39.9042,    // 北纬 39.9042°
  "longitude": 116.4074,  // 东经 116.4074°
  "altitude": 50.0,       // 相对起飞点 50 米
  "altitudeType": "relative" // relative 或 absolute
}

3.2 航点动作:到了点要干什么

飞机飞到航点后,可以执行一系列动作。我个人习惯把动作分成三类:

动作类型 典型动作 说明
云台动作 俯仰、偏航、回中 控制相机朝向
拍照/录像 单拍、连拍、开始录像、停止录像 数据采集核心
飞行器动作 悬停、降落、返航、设置航向 改变飞行状态

动作的执行顺序也很重要。我一般建议:先调整云台,再拍照,最后做飞行器动作。为什么?因为云台稳定需要时间,拍完照再动飞机,画面不会糊。

小技巧:如果你做测绘,每个航点建议加一个「云台俯仰 -90°」的动作,保证相机正对地面。我曾经漏了这个参数,飞了 200 个航点,回来发现一半照片是天空。

// 航点动作示例
"actions": [
  {
    "actionType": "gimbalPitch",
    "actionParam": -90,  // 云台俯仰 -90°(正对地面)
    "actionDelay": 1     // 动作执行前等待 1 秒
  },
  {
    "actionType": "takePhoto",
    "actionParam": 0,    // 单拍
    "actionDelay": 0
  }
]

3.3 航点参数:速度、高度与悬停时间

这部分是航点任务的「调性」所在。同样的航线,参数不同,飞出来的效果天差地别。

3.3.1 速度

速度分两种:航段速度和航点速度。

  • 航段速度:飞机从一个航点到下一个航点的飞行速度
  • 航点速度:飞机到达航点后,执行动作时的速度(通常为 0,即悬停)

我建议航段速度控制在 5-15 m/s 之间。太快了,照片容易模糊;太慢了,电池扛不住。

注意:转弯处的速度要单独处理。我曾经设了 12 m/s 的航段速度,结果在 90° 转弯处飞机差点侧翻。后来我加了转弯半径参数,才把问题解决。

3.3.2 高度

高度参数可以每个航点单独设置,也可以整条航线统一。我个人习惯:

  • 平坦地形:统一高度,省事
  • 起伏地形:每个航点单独设高度,跟随地形

高度变化率也要注意。一般不超过 5 m/s,否则飞控容易触发高度保护。

3.3.3 悬停时间

悬停时间,就是飞机在航点停留的秒数。这个参数直接影响任务总时长。

举个例子:

// 悬停时间参数
"hoverTime": 2  // 单位:秒,范围 0-3600

如果每个航点悬停 2 秒,100 个航点就是 200 秒。再加上飞行时间,总时长很容易超过电池极限。所以,非必要不悬停。

3.4 完整航点数据结构示例

把上面所有东西拼起来,一个完整的航点数据大概长这样:

{
  "waypoints": [
    {
      "latitude": 39.9042,
      "longitude": 116.4074,
      "altitude": 50.0,
      "altitudeType": "relative",
      "speed": 10.0,           // 航段速度 10 m/s
      "hoverTime": 2,          // 悬停 2 秒
      "headingMode": "auto",   // 航向模式:auto/fixed/target
      "actions": [
        {
          "actionType": "gimbalPitch",
          "actionParam": -90,
          "actionDelay": 1
        },
        {
          "actionType": "takePhoto",
          "actionParam": 0,
          "actionDelay": 0
        }
      ]
    }
    // ... 更多航点
  ],
  "globalParams": {
    "defaultSpeed": 12.0,      // 默认航段速度
    "defaultHoverTime": 0,     // 默认悬停时间
    "finishAction": "hover",   // 任务结束动作:hover/return/land
    "exitOnRCLost": "return"   // 遥控器信号丢失后:hover/return/land
  }
}

核心原则:全局参数作为兜底,航点参数作为覆盖。如果某个航点没设 speed,就沿用全局的 defaultSpeed。这样既灵活又简洁。

3.5 知识体系总览

下面这张图把航点数据结构的核心逻辑串起来了。你一看就明白:

航点数据结构知识体系 航点数据结构核心逻辑 航点 (Waypoint) 坐标 (Lat/Lon/Alt) 动作 (Actions) 参数 (Speed/Hover/Heading) 纬度/经度/海拔 相对高/绝对高 云台/拍照/飞行器 动作延迟/执行顺序 航段速度/航点速度 悬停时间/航向模式 全局参数兜底 + 航点参数覆盖 = 灵活可控的航线

3.6 避坑指南

最后,分享几个我踩过的坑:

  • 坐标系统一:整个任务必须用同一个坐标系。WGS84 和 GCJ02 混用?飞机直接飞偏。
  • 海拔检查:相对高要确保起飞点海拔正确。我在高原飞过一次,忘了调基准面,飞机差点撞山。
  • 动作超时:每个动作最好设一个超时时间。比如云台俯仰,如果 5 秒没到位,直接跳过。否则飞机一直等,电池耗光。
  • 悬停时间别太长:超过 30 秒的悬停,建议拆成多个航点。为什么?因为风大的时候,飞机悬停会飘,影响后续航线精度。

我的习惯:每次写航点任务前,先画一张数据结构的草图。把坐标、动作、参数列清楚,再动手编码。这样能避免 80% 的 bug。

好了,航点数据结构就讲到这里。你只要把坐标、动作、参数这三个维度理清楚,剩下的就是填参数的事了。记住:结构清晰,任务才稳。