322 lines
14 KiB
C++
322 lines
14 KiB
C++
#ifndef GLOBAL_H
|
||
#define GLOBAL_H
|
||
|
||
#include <QString>
|
||
#include <QStringList>
|
||
#include <QVector>
|
||
#include <QWidget>
|
||
#include <QTimer>
|
||
#include <QVariant>
|
||
#include <QColor>
|
||
|
||
class QApplication;
|
||
|
||
// ===================== 画布与全局常量 =====================
|
||
// 屏幕分辨率(1920×1200);窗口按此固定尺寸,页面布局靠 layout 自适应,
|
||
// 富余的垂直空间由各页的 addStretch 分配(控件像素尺寸与字号不随屏幕缩放)
|
||
static const int SCREEN_W = 1920;
|
||
static const int SCREEN_H = 1200;
|
||
|
||
// ===================== 工业风格配色体系(QSS 十六进制) =====================
|
||
namespace C {
|
||
const QString BG = "#161C23"; // 主背景:窗口画布底色
|
||
const QString PANEL = "#242E3A"; // 面板背景:卡片/弹窗/顶条/底条
|
||
const QString PANEL_HI = "#2D3947"; // 面板亮色:按钮常态、表头、进度条底
|
||
const QString BORDER = "#3D4A59"; // 分割线:边框、表格线
|
||
const QString TEXT = "#E6EDF3"; // 主文字:标题、正文、数值
|
||
const QString TEXT_SUB = "#9AA7B4"; // 次文字:说明、单位、标签
|
||
const QString PRIMARY = "#3D8BFD"; // 强调主色:主按钮、选中、焦点、进度条
|
||
const QString SUCCESS = "#36C75A"; // 成功/运行:运行、开启、到位
|
||
const QString WARNING = "#F5A623"; // 警告:提醒、待确认
|
||
const QString DANGER = "#E5484D"; // 危险/故障:急停、故障、警示
|
||
const QString DISABLED = "#56636F"; // 禁用:不可操作控件底色
|
||
const QString DISABLED_T = "#6B7A88"; // 禁用文字
|
||
}
|
||
|
||
// ===================== 操作模式 =====================
|
||
// 面板机械旋钮切换:行车模式 / 机械臂模式
|
||
enum class Mode { Drive = 0, Arm = 1 };
|
||
|
||
// ===================== 页面枚举(QStackedWidget 索引) =====================
|
||
enum PageId {
|
||
PageBoot = 0, // ③ 开机密码
|
||
PageWarning, // 密码警告
|
||
PageMgmtLogin, // 密码管理登录
|
||
PageMgmt, // 密码管理
|
||
PageReset, // 密码重置
|
||
PageSelfCheck, // ④ 自检
|
||
PageHome, // ⑤ 系统首页面(自检完成后进入)
|
||
PageJob, // ⑥ 作业选择
|
||
PageChassis, // ⑦ 机器人底盘
|
||
PageArm, // ⑧ 机械臂
|
||
PageGas, // ⑨ 气体检测仪
|
||
PageClean, // ⑩ 消除作业
|
||
PageDisinfect, // ⑪ 消毒作业
|
||
PageDebug, // ⑫ 调试维护
|
||
PageFault, // ⑬ 故障查询
|
||
PageCount
|
||
};
|
||
|
||
// ===================== 遥测数据(车载端 → UI) =====================
|
||
// 由通信层解析车端反馈报文后填充,页面刷新时读取。
|
||
// 这里不留任何演示初值:数值字段只由报文写入,配套的 has* 标志在收到对应报文时置位,
|
||
// 页面按 dashIf() 判断“还没有值”,未收到时显示 "--"。
|
||
struct Telemetry {
|
||
// 底盘
|
||
int soc = 0; // 电量 %
|
||
double volt = 0.0; // 电压 V
|
||
double speed = 0.0; // 车速 km/h
|
||
bool handbrake = false; // 手刹
|
||
int driveMode = 0; // 行车/机械臂模式:0=行车 1=机械臂(遥控器拨钮→串口→底盘报文 mode)
|
||
int rdyStatus = 0; // 底盘 ready:0=初始 1=高压上电完成 2=准备就绪
|
||
int gearPos = 0; // 挡位:0=N 1=D 2=R
|
||
int parking = 0; // 驻车:0=未驻车 1=左电机 2=右电机 3=完全驻车
|
||
int awdMode = 0; // 四驱模式:0=二驱 1=四驱 2=四驱锁定
|
||
double steerAngle = 0.0; // 方向盘角度
|
||
int alignStatus = 0; // 角度对中状态:0x11=对中失败、0xEE/0x55=成功、其它=未对中
|
||
QStringList chassisFaults; // 底盘故障(多条 2s 轮换)
|
||
|
||
// 机械臂
|
||
QVector<double> js{0, 0, 0, 0, 0, 0}; // 关节角 J1~J6(°)
|
||
QString pos = "--"; // 末端位置 XYZ
|
||
QString pose = "--"; // 姿态 RX/RY/RZ
|
||
double vel = 0.0; // 末端速度
|
||
QString returnState = "idle";// 回位状态 idle/returning/done/fault
|
||
bool armHomed = false; // 是否已回位(用于底盘“机械臂未回位”告警)
|
||
|
||
// 洗消
|
||
QString washMode = "--"; // 手动消除 / 手动消毒
|
||
bool washStart = false; // 洗消启停反馈
|
||
double flowA = 0.0; // A 药剂流量 L/min
|
||
double flowB = 0.0; // B 药剂流量 L/min
|
||
double gasFlow = 0.0; // 气体流量 L/min
|
||
double press = 0.0; // 管路压力 MPa
|
||
double airPress = 0.0; // 空压机压力 MPa
|
||
double foam = 0.0; // 发泡倍数
|
||
double flowPlungerFb = 0.0; // 柱塞泵流量反馈 L/min
|
||
double flowAirFb = 0.0; // 空压机流量反馈 L/min
|
||
double flowVaneFb = 0.0; // 叶片泵流量反馈 L/min
|
||
QStringList washFaults; // 洗消故障代码
|
||
|
||
// 液位
|
||
double levelA = 0.0; // 清水/药剂液位 L
|
||
double levelFoam = 0.0; // 泡沫液位 L
|
||
bool levelALow = false; // A组分/清水液位低(A_LiquidLevel_Low)
|
||
bool levelBLow = false; // B组分/泡沫液位低(B_LiquidLevel_Low)
|
||
|
||
// 气体检测仪
|
||
QString gasHost; // 主机状态 standby/detecting/fault,空=未收到
|
||
QString gasType = "--"; // 有毒物种类
|
||
QString gasLevel = "--"; // 有毒物等级
|
||
double gasConc = 0.0; // 有毒物浓度 ppb
|
||
|
||
// 球阀 D1/D2
|
||
bool d1open = false; // D1 开启到位
|
||
bool d1close = true; // D1 关闭到位
|
||
bool d2open = false; // D2 开启到位
|
||
bool d2close = true; // D2 关闭到位
|
||
|
||
// 泵
|
||
bool plunger = false; // 柱塞泵上电
|
||
bool air = false; // 空压机上电
|
||
bool leaf = false; // 叶片泵上电
|
||
QStringList pumpFaults; // 泵故障代码
|
||
|
||
// 气体检测仪故障。单列一份、不并进 washFaults:洗消页底栏的“系统故障”灯
|
||
// 只看洗消系统与泵,气体检测仪的告警要归到它自己的卡片上。
|
||
QStringList detectorFaults;
|
||
|
||
// 遥控器(24 字节二进制帧,见 comm/uart.h)
|
||
bool rcLinkOk = false; // 遥控器链路是否在线
|
||
int rcBattery = 0; // 遥控器电量 %
|
||
bool rcDriveMode = false; // bit0 行车模式
|
||
bool rcArmMode = false; // bit1 机械臂模式
|
||
bool rcArmEnabled = false; // bit2 机械臂使能
|
||
bool rcChassisEnabled = false;// bit3 底盘使能
|
||
bool rcEstop = false; // bit4 急停
|
||
int rcGear = 2048; // 整车档位(底盘 Y)0~4096,中位 2048
|
||
int rcSteer = 2048; // 整车转向(底盘 X)
|
||
int rcPosZ = 2048; // 末端位置上下
|
||
int rcPosX = 2048; // 末端位置左右
|
||
int rcPosY = 2048; // 末端位置前后
|
||
int rcRoll = 2048; // 末端姿态横滚
|
||
int rcPitch = 2048; // 末端姿态俯仰
|
||
int rcYaw = 2048; // 末端姿态偏航
|
||
|
||
// 全局
|
||
bool commOk = true; // 通信状态
|
||
bool estop = false; // 急停触发
|
||
|
||
// 顶部左区固定显示的一行通信状态,由 CarCommunication 渲染:
|
||
// 链路正常且 All_Comm_FaultCode=0 → “系统通信正常”;有码 → 该码的文案
|
||
// (“机械臂通信异常”…);链路断开、没有码 → “通信异常”。
|
||
// 各项子系统故障明细不在这里,而是各自进对应卡片的“故障”行。
|
||
QString commText = QString::fromUtf8("系统通信正常");
|
||
int commCode = 0; // All_Comm_FaultCode 原值,0 = 通信正常
|
||
|
||
// ---- 各报文是否已收到 ----
|
||
// CarCommunication 每解析到一条报文就置位对应的 has*,页面按它决定“还没有值”时显示 "--"。
|
||
// 按“一条报文覆盖哪些显示项”分组,而不是每个字段一个标志。
|
||
bool hasBattery = false; // 0x18308180 底盘状态1:电量 / 电压
|
||
bool hasSpeed = false; // 0x18318180 底盘状态2:车速 / 手刹 / Ready状态
|
||
bool hasChassis4 = false; // 0x183B8180 底盘状态4:挡位 / 驻车 / 四驱 / 方向盘角度
|
||
bool hasArmPose = false; // 0x18338180 机械臂状态2:末端速度
|
||
bool hasJoints = false; // 0x18348180 / 0x18358180:关节角 J1~J6
|
||
bool hasWash = false; // 0x18368180 洗消状态1:液位 / 流量 / 发泡倍数
|
||
bool hasWashPress= false; // 0x18378180 洗消状态2:管路压力 / 空压机压力
|
||
bool hasGasHost = false; // 0x18388180 检测仪状态1:主机状态
|
||
bool hasGasConc = false; // 0x18398180 检测仪状态2:有毒物浓度
|
||
};
|
||
|
||
// 遥测未收到(has* 为 false)时统一显示 "--"
|
||
inline QString dashIf(bool has, const QString& text)
|
||
{
|
||
return has ? text : QStringLiteral("--");
|
||
}
|
||
|
||
// 气体检测仪主机状态 → 显示文案
|
||
inline QString gasHostLabel(const Telemetry& t)
|
||
{
|
||
if (!t.hasGasHost) return QStringLiteral("--");
|
||
return t.gasHost == "detecting" ? QString::fromUtf8("检测中")
|
||
: t.gasHost == "fault" ? QString::fromUtf8("故障")
|
||
: QString::fromUtf8("待机");
|
||
}
|
||
|
||
// 洗消卡片“故障”行的内容:洗消系统与泵都算它,气体检测仪另走一份 detectorFaults。
|
||
inline QStringList washCardFaults(const Telemetry& t)
|
||
{
|
||
return t.washFaults + t.pumpFaults;
|
||
}
|
||
|
||
// ---- 底盘的几个枚举信号 → 显示文案(取值见协议「信号值描述」列) ----
|
||
inline QString gearLabel(int v)
|
||
{
|
||
return v == 1 ? QString::fromUtf8("D挡")
|
||
: v == 2 ? QString::fromUtf8("R挡")
|
||
: QString::fromUtf8("N挡");
|
||
}
|
||
|
||
inline QString parkingLabel(int v)
|
||
{
|
||
switch (v) {
|
||
case 1: return QString::fromUtf8("左电机驻车");
|
||
case 2: return QString::fromUtf8("右电机驻车");
|
||
case 3: return QString::fromUtf8("完全驻车");
|
||
default: return QString::fromUtf8("未驻车");
|
||
}
|
||
}
|
||
|
||
inline QString awdLabel(int v)
|
||
{
|
||
return v == 1 ? QString::fromUtf8("四驱")
|
||
: v == 2 ? QString::fromUtf8("四驱锁定")
|
||
: QString::fromUtf8("二驱");
|
||
}
|
||
|
||
inline QString rdyLabel(int v)
|
||
{
|
||
return v == 1 ? QString::fromUtf8("高压上电完成")
|
||
: v == 2 ? QString::fromUtf8("准备就绪")
|
||
: QString::fromUtf8("初始状态");
|
||
}
|
||
|
||
// Angle_alignment_status:0 是"还没做过",与失败要分清楚。
|
||
// 文案比协议描述短一点("未进行过角度对中"→"未进行过对中"):标签已经写了"角度对中状态",
|
||
// 值里再重复一遍就溢出行宽了(底盘卡正文区 548px)。
|
||
inline QString alignLabel(int v)
|
||
{
|
||
switch (v) {
|
||
case 0x11: return QString::fromUtf8("角度对中失败");
|
||
case 0xEE: return QString::fromUtf8("角度对中成功");
|
||
case 0x55: return QString::fromUtf8("已对中成功");
|
||
default: return QString::fromUtf8("未进行过对中");
|
||
}
|
||
}
|
||
|
||
// ===================== 全局闪烁节拍 =====================
|
||
// 界面上有好几处在“异常闪烁”:顶部通信状态、卡片故障行、告警横幅、底栏指示灯、
|
||
// 自检结果……各自起定时器的话相位互不相同,同一屏上会各闪各的。
|
||
// 这里做成**一个**公共节拍,所有闪烁都挂在它上面:整屏同时亮、同时灭。
|
||
// 要改闪烁快慢只改这一处的 interval(500ms)。
|
||
class BlinkBeat : public QObject
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
static BlinkBeat* instance();
|
||
|
||
bool on() const { return m_on; } // 当前是“亮”还是“灭”,供刚订阅上来的对齐相位
|
||
|
||
signals:
|
||
void toggled(bool on);
|
||
|
||
private:
|
||
explicit BlinkBeat(QObject* parent = nullptr);
|
||
|
||
QTimer* m_timer = nullptr;
|
||
bool m_on = true;
|
||
};
|
||
|
||
// ===================== 工具函数 =====================
|
||
// 启动闪烁:挂到全局节拍上,每拍翻转一次动态属性(40% ↔ 100% 透明度由 QSS 规则体现)
|
||
void startBlink(QWidget* w, const char* prop = "blink");
|
||
|
||
// 退订全局节拍并复位属性
|
||
void stopBlink(QWidget* w, const char* prop = "blink");
|
||
|
||
// 退出/取消按钮预设样式:被选中(悬停/按下/焦点)时红底白字
|
||
QString cancelButtonStyle(int fontPx = 60);
|
||
|
||
// ===================== 本机按键 =====================
|
||
// 面板只提供 5 个键:Tab、Shift+Tab、空格、方向上、方向下。
|
||
// 新增按键或调整键位只改这一处。
|
||
namespace Keys {
|
||
inline bool tab(int k) { return k == Qt::Key_Tab; }
|
||
inline bool backtab(int k) { return k == Qt::Key_Backtab; } // Shift+Tab
|
||
inline bool shifted(int mods) { return (mods & Qt::ShiftModifier) != 0; }
|
||
inline bool space(int k) { return k == Qt::Key_Space; }
|
||
inline bool up(int k) { return k == Qt::Key_Up; }
|
||
inline bool down(int k) { return k == Qt::Key_Down; }
|
||
}
|
||
|
||
// ===================== 按钮焦点(选中)光圈 =====================
|
||
// 全局事件过滤器:任意 QPushButton 获得焦点时,在其四周加一圈发光;
|
||
// 同时把"触摸/点击"与"Tab"归一到同一个焦点,并清除触摸残留在按钮上的悬停态,
|
||
// 保证任意时刻只有一个按钮呈选中样式(新的操作覆盖原来的)。
|
||
class ButtonFocusGlow : public QObject
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
explicit ButtonFocusGlow(const QColor& glow = QColor("#3D8BFD"), QObject* parent = nullptr);
|
||
|
||
protected:
|
||
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||
|
||
private:
|
||
QColor m_glow;
|
||
};
|
||
|
||
// 为整个应用安装按钮焦点光圈
|
||
void installButtonFocusGlow(QApplication* app);
|
||
|
||
// ===================== 方向键(旋钮)隔离 =====================
|
||
// 上/下方向键在本机是"旋钮"键位,只由 ParamControl 用来调值。
|
||
// 这个全局过滤器把"焦点在按钮上时"的方向键吞掉,方向键只做调值、换焦只走 Tab。
|
||
class ArrowKeyGuard : public QObject
|
||
{
|
||
Q_OBJECT
|
||
public:
|
||
explicit ArrowKeyGuard(QObject* parent = nullptr);
|
||
|
||
protected:
|
||
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||
};
|
||
|
||
// 为整个应用安装方向键隔离
|
||
void installArrowKeyGuard(QApplication* app);
|
||
|
||
// 全局 QSS 样式表
|
||
QString appStyleSheet();
|
||
|
||
#endif // GLOBAL_H
|