一、转速表的核心内容与设计原理
1.1 转速表的功能定位
在无人机地面站系统中,转速表(Tachometer)是核心监控仪表之一,主要用于实时显示动力系统的运转状态。对于多旋翼无人机,转速表通常监控以下对象:
- 电机转速(RPM):直接反映电机工作状态,典型范围为 10,000-50,000RPM(取决于电机 KV 值、电池电压和螺旋桨负载)。
- 异常检测:通过对比多电机转速差异(如偏差超过 15%)预警螺旋桨失衡、电调故障或电池老化。
- 性能评估:分析不同飞行阶段(如起飞、悬停、降落)的转速变化,优化 PID 参数或更换螺旋桨。
1.2 关键技术指标
- 测量精度:±1%~±5%(飞控从电调反馈)
- 采样频率:≥100Hz(穿越机需 500Hz 以上以捕捉高频波动)
- 显示范围:0-50,000RPM(覆盖常见无人机电机工作区间)
- 响应时间:<10ms(确保快速捕捉转速突变)
1.3 设计意图与安全意义
转速表不仅是数据显示工具,更是无人机安全飞行的保障:
- 起飞阶段:检查各电机转速同步性(差异 > 5% 可能导致偏航)
- 巡航阶段:稳定转速突然下降可能预示电池耗尽或电机效率降低
- 降落阶段:转速响应延迟可能导致着陆冲击过大
1.4 行业标准与规范
- RTCA DO-178C:航空软件安全性标准,要求转速数据处理具备冗余校验
- EUROCAE ED-12C:航空电子设备设计规范,规定仪表显示刷新率≥30Hz
- FAA Part 23:小型无人机适航标准,要求转速表具备故障安全机制
二、基于 Qt/C++ 与 QML 的转速表开发方案
2.1 技术选型理由
- Qt 框架:跨平台(支持 Windows/macOS/Linux/ 嵌入式)、高性能 UI 渲染、丰富的传感器接口库
- QML:声明式语言,简化 UI 开发,支持动画、3D 效果和响应式布局
- C++:底层数据处理高效,适合实时系统开发
2.2 系统架构设计
plaintext
┌─────────────────────────────────────────────────┐
│ 地面站应用 │
├─────────────────────────┬───────────────────────┤
│ C++ 后端逻辑 │ QML 前端界面 │
│ (数据处理/算法/通信) │ (UI渲染/交互/动画) │
├─────────────────────────┴───────────────────────┤
│ Qt 框架层 │
│ (Core/Network/SerialPort/Charts/Multimedia) │
└─────────────────────────────────────────────────┘
2.3 数据模型设计(C++ 部分)
cpp
运行
// MotorData.h
#ifndef MOTORDATA_H
#define MOTORDATA_H
#include <QObject>
#include <QVector>
#include <QTimer>
class MotorData : public QObject
{
Q_OBJECT
Q_PROPERTY(int motorId READ motorId CONSTANT)
Q_PROPERTY(double currentRpm READ currentRpm NOTIFY rpmChanged)
Q_PROPERTY(QString status READ status NOTIFY statusChanged)
public:
explicit MotorData(int id, QObject *parent = nullptr);
int motorId() const;
double currentRpm() const;
QString status() const;
QVector<double> rpmHistory() const;
void addRpm(double rpm);
signals:
void rpmChanged();
void statusChanged();
public slots:
void simulateData();
private:
int m_motorId;
double m_currentRpm;
QString m_status;
QVector<double> m_rpmHistory;
QTimer* m_simulatorTimer;
};
// MotorData.cpp
#include "MotorData.h"
#include <QRandomGenerator>
#include <QtMath>
MotorData::MotorData(int id, QObject *parent) : QObject(parent), m_motorId(id), m_currentRpm(0)
{
m_status = "正常";
// 模拟数据更新(实际应用中应通过串口或网络接收真实数据)
m_simulatorTimer = new QTimer(this);
connect(m_simulatorTimer, &QTimer::timeout, this, &MotorData::simulateData);
m_simulatorTimer->start(100); // 10Hz更新频率
}
int MotorData::motorId() const
{
return m_motorId;
}
double MotorData::currentRpm() const
{
return m_currentRpm;
}
QString MotorData::status() const
{
return m_status;
}
QVector<double> MotorData::rpmHistory() const
{
return m_rpmHistory;
}
void MotorData::addRpm(double rpm)
{
if (qFuzzyCompare(m_currentRpm, rpm))
return;
m_currentRpm = rpm;
m_rpmHistory.append(rpm);
// 保持历史数据长度不超过1000个点
if (m_rpmHistory.size() > 1000)
m_rpmHistory.removeFirst();
// 状态检测
if (rpm < 5000)
m_status = "停机";
else if (rpm > 40000)
m_status = "高负载";
else
m_status = "正常";
emit rpmChanged();
emit statusChanged();
}
void MotorData::simulateData()
{
// 模拟电机转速数据
double baseRpm = 25000 + QRandomGenerator::global()->bounded(-1000, 1000);
// 模拟电机1故障(转速波动大)
if (m_motorId == 1 && QRandomGenerator::global()->bounded(10) < 2)
baseRpm *= QRandomGenerator::global()->bounded(0.7, 1.3);
addRpm(baseRpm);
}
2.4 QML 界面实现
qml
// Tachometer.qml
import QtQuick 2.15
import QtCharts 2.15
Item {
id: tachometer
width: 300
height: 300
property double maxRpm: 50000
property double currentRpm: 0
property string status: "正常"
// 颜色定义
property color normalColor: "#4CAF50"
property color warningColor: "#FFC107"
property color dangerColor: "#F44336"
// 计算角度(135度到-135度范围)
property double angle: 135 - (currentRpm/maxRpm) * 270
// 表盘背景
Rectangle {
id: gaugeBackground
width: parent.width
height: parent.height
radius: width/2
color: "#2A2A2A"
border.color: "#444444"
border.width: 2
// 刻度
Repeater {
model: 51 // 0-50刻度
Rectangle {
width: index % 10 === 0 ? 10 : 5
height: index % 10 === 0 ? 30 : 20
color: "#CCCCCC"
radius: 2
x: parent.width/2 - width/2
y: 10
rotation: index * 5.4 // 270度范围,51个刻度
transformOrigin: Item.Center
}
}
// 刻度标签
Repeater {
model: