第四章:地面站与指挥中心搭建

4.1 为什么地面站这么重要?

说实话,很多人觉得地面站就是个遥控器的大屏版。其实不是。

我参与的第一个风电巡检项目,团队花了两个月调飞控,结果第一次实地测试就翻车了——无人机在天上飞得好好的,地面站却显示「信号丢失」。后来发现,不是通信问题,是地面站软件对特定机型的MAVLink消息解析有bug。

从那天起我就明白:地面站不是附属品,它是整个系统的神经中枢。你想想看,无人机在天上飞,所有状态数据、控制指令、任务规划,全都要经过地面站。地面站挂了,无人机就是断了线的风筝。

4.2 QGroundControl二次开发:从入门到实战

QGroundControl(以下简称QGC)是目前最成熟的开源地面站之一。我选择它作为基础平台,原因有三:

  • 协议支持全:MAVLink 1.0/2.0全覆盖,主流飞控都能接
  • 架构清晰:Qt + C++,插件化设计,扩展方便
  • 社区活跃:遇到问题基本都能找到答案

4.2.1 开发环境搭建

我个人习惯用Qt 5.15 + MSVC 2019这套组合。为什么不用Qt 6?嗯,QGC对Qt 6的支持还在完善中,有些插件会报错。别问我怎么知道的——我踩过这个坑。

# 克隆源码
git clone --recursive https://github.com/mavlink/qgroundcontrol.git
cd qgroundcontrol

# 安装依赖(Windows环境)
pip install -r requirements.txt

# 编译
mkdir build && cd build
cmake .. -G "Visual Studio 16 2019" -A x64
cmake --build . --config Release
注意:编译时一定要加 --recursive 参数拉取子模块。我见过有人漏了这一步,结果编译到一半报错找不到MAVLink库,白白浪费半小时。

4.2.2 核心二次开发点

针对风电巡检场景,我们需要在QGC基础上做这些改造:

模块 改造内容 关键文件
地图引擎 替换为离线地图(风电场常无网络) QmlMapEngine.cc
任务规划 添加风机巡检航线模板 MissionController.cc
数据展示 增加风机状态叠加层 Vehicle.cc
通信模块 支持多机同时连接 LinkManager.cc

举个例子,添加风机巡检航线模板时,我写了个简单的航线生成函数:

// 生成风机巡检航线(三点环绕法)
QList<QGeoCoordinate> generateTurbineInspectionPath(
    const QGeoCoordinate& turbineCenter,
    double radius,       // 环绕半径(米)
    double altitude,     // 飞行高度(米)
    int pointsPerCircle // 每圈采样点
) {
    QList<QGeoCoordinate> path;
    double angleStep = 2 * M_PI / pointsPerCircle;
    
    for (int i = 0; i < pointsPerCircle; ++i) {
        double angle = i * angleStep;
        double latOffset = radius * cos(angle) / 111320.0;
        double lonOffset = radius * sin(angle) / (111320.0 * cos(turbineCenter.latitude() * M_PI / 180.0));
        
        QGeoCoordinate point(
            turbineCenter.latitude() + latOffset,
            turbineCenter.longitude() + lonOffset,
            altitude
        );
        path.append(point);
    }
    return path;
}
小技巧:实际项目中,我建议把风机坐标存在一个JSON文件里,地面站启动时自动加载。这样换风场时不用重新编译代码,改个配置文件就行。

4.3 Web端指挥大屏设计

地面站是给飞手用的,指挥大屏是给项目经理看的。两者定位完全不同。

指挥大屏的核心需求就三个:全局态势感知、多机状态监控、异常告警。说白了,就是让领导一眼看清「现在几台机子在飞、飞得怎么样、有没有出问题」。

4.3.1 技术选型

我推荐用这套技术栈:

  • 前端框架:Vue 3 + TypeScript(生态成熟,组件库丰富)
  • 地图引擎:Leaflet + 离线瓦片(风电场网络差,你懂的)
  • 实时通信:WebSocket(从QGC转发数据到Web端)
  • 数据可视化:ECharts(画仪表盘、趋势图很顺手)

4.3.2 核心功能模块

我设计的指挥大屏通常包含这几个区域:

  1. 地图区:显示所有无人机实时位置、航线、风机点位
  2. 状态面板:每台无人机的电量、信号强度、飞行模式
  3. 告警列表:实时滚动显示异常事件(低电量、信号丢失、GPS丢星)
  4. 统计看板:今日巡检架次、完成率、平均耗时

这里有个关键点——数据流设计。我曾经见过一个方案,Web端直接连飞控,结果飞控的MAVLink数据量太大,浏览器直接卡死。正确的做法是:

无人机 → QGC(数据聚合) → WebSocket Server → 指挥大屏

QGC作为数据中继,把原始MAVLink消息解析成JSON格式,再推送给Web端。这样Web端只处理业务数据,压力小很多。

4.3.3 实时数据推送实现

在QGC里添加WebSocket服务端,代码大概这样:

// WebSocketServer.h
class WebSocketServer : public QObject {
    Q_OBJECT
public:
    explicit WebSocketServer(quint16 port = 9090);
    
public slots:
    void onVehicleUpdated(const QJsonObject& vehicleData);
    
private:
    QWebSocketServer* m_server;
    QList<QWebSocket*> m_clients;
};

// WebSocketServer.cpp
void WebSocketServer::onVehicleUpdated(const QJsonObject& vehicleData) {
    QByteArray message = QJsonDocument(vehicleData).toJson();
    for (auto client : m_clients) {
        client->sendTextMessage(message);
    }
}

前端接收数据后,用ECharts实时更新仪表盘:

// 前端代码(Vue 3)
const ws = new WebSocket('ws://localhost:9090');
ws.onmessage = (event) => {
    const data = JSON.parse(event.data);
    // 更新地图标记
    updateMarker(data.vehicleId, data.lat, data.lng);
    // 更新电量仪表
    batteryGauge.setValue(data.batteryPercent);
    // 检查告警
    if (data.batteryPercent < 20) {
        addAlert(`无人机 ${data.vehicleId} 电量不足`);
    }
};
核心原则:指挥大屏只做「展示」和「告警」,不做「控制」。控制指令必须由地面站发出,这是安全底线。

4.4 系统架构总览

说了这么多,咱们用一张图把整个体系串起来:

多机协同风电巡检系统架构 无人机层 无人机 #1 无人机 #2 无人机 #3 无人机 #N MAVLink 协议(数传电台/4G) 地面站层(QGC二次开发) 航线规划 状态监控 数据聚合 WebSocket服务 离线地图 多机管理 JSON转换 数据推送 WebSocket(JSON格式) 指挥大屏层(Web端) 态势地图 状态仪表 告警列表 统计看板 Leaflet ECharts 实时滚动 Vue 3

这张图我画了好几个版本才定下来。你看,数据从无人机出发,经过QGC地面站聚合处理,再通过WebSocket推送到指挥大屏。每一层各司其职,互不干扰。

4.5 避坑指南

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

  • 离线地图要提前准备:风电场通常在山沟里,4G信号时有时无。我建议用QGIS下载好18级瓦片,打包成MBTiles格式,QGC直接加载本地文件。
  • WebSocket断线重连:网络不稳定是常态。前端一定要实现自动重连机制,我一般设置3秒重试间隔,最多重试10次。
  • 数据频率控制:无人机位置数据每秒更新10次,全部推给Web端会撑爆带宽。我在QGC里做了降采样——位置数据每秒推2次,状态数据每秒推1次,告警数据实时推。
  • 多机ID管理:每台无人机要有唯一标识。我习惯用飞控的MAVLink系统ID(sysid),配合自定义的机组编号,比如「WF-01-03」表示风场1的第3台机子。
我的建议:第一次做二次开发,别想着一步到位。先跑通QGC的Hello World插件,再逐步添加功能。我当年就是太心急,一上来就改核心代码,结果编译都过不了。

嗯,地面站和指挥大屏这块,核心思路就是「分层解耦」。QGC负责和无人机打交道,Web端负责和人打交道。中间用WebSocket搭座桥,两边各干各的活,清爽又稳定。

专注资料整理