新版布局

This commit is contained in:
xu
2026-10-16 09:06:03 +08:00
parent e5efdea06e
commit 1ec93e42cb
37 changed files with 1785 additions and 977 deletions
+130 -13
View File
@@ -58,23 +58,26 @@ enum PageId {
};
// ===================== 遥测数据(车载端 → UI) =====================
// 由通信层解析车端反馈报文后填充,页面刷新时读取
// 由通信层解析车端反馈报文后填充,页面刷新时读取。
// 这里不留任何演示初值:数值字段只由报文写入,配套的 has* 标志在收到对应报文时置位,
// 页面按 dashIf() 判断“还没有值”,未收到时显示 "--"。
struct Telemetry {
// 底盘
int soc = 85; // 电量 %
double volt = 360.0; // 电压 V
double speed = 3.45; // 车速 km/h
bool handbrake = true; // 手刹
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{30, 20, 0, 90, 45, 0}; // 关节角 J1~J6(°)
QVector<double> js{0, 0, 0, 0, 0, 0}; // 关节角 J1~J6(°)
QString pos = "--"; // 末端位置 XYZ
QString pose = "--"; // 姿态 RX/RY/RZ
double vel = 0.0; // 末端速度
@@ -96,11 +99,13 @@ struct Telemetry {
QStringList washFaults; // 洗消故障代码
// 液位
double levelA = 100.0; // 清水/药剂液位 L
double levelFoam = 30.0; // 泡沫液位 L
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"; // 主机状态 standby/detecting/fault
QString gasHost; // 主机状态 standby/detecting/fault,空=未收到
QString gasType = "--"; // 有毒物种类
QString gasLevel = "--"; // 有毒物等级
double gasConc = 0.0; // 有毒物浓度 ppb
@@ -110,7 +115,6 @@ struct Telemetry {
bool d1close = true; // D1 关闭到位
bool d2open = false; // D2 开启到位
bool d2close = true; // D2 关闭到位
QString valveFault; // 球阀故障码
// 泵
bool plunger = false; // 柱塞泵上电
@@ -118,6 +122,10 @@ struct Telemetry {
bool leaf = false; // 叶片泵上电
QStringList pumpFaults; // 泵故障代码
// 气体检测仪故障。单列一份、不并进 washFaults:洗消页底栏的“系统故障”灯
// 只看洗消系统与泵,气体检测仪的告警要归到它自己的卡片上。
QStringList detectorFaults;
// 遥控器(24 字节二进制帧,见 comm/uart.h)
bool rcLinkOk = false; // 遥控器链路是否在线
int rcBattery = 0; // 遥控器电量 %
@@ -138,13 +146,122 @@ struct Telemetry {
// 全局
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;
};
// ===================== 工具函数 =====================
// 启动 500ms 闪烁:每 500ms 切换一次 QSS 动态属性(40% ↔ 100% 透明度由 QSS 规则体现)
QTimer* startBlink(QWidget* w, const char* prop = "blink");
// 启动闪烁:挂到全局节拍上,每拍翻转一次动态属性(40% ↔ 100% 透明度由 QSS 规则体现)
void startBlink(QWidget* w, const char* prop = "blink");
// 关闭闪烁定时器并复位属性
// 退订全局节拍并复位属性
void stopBlink(QWidget* w, const char* prop = "blink");
// 退出/取消按钮预设样式:被选中(悬停/按下/焦点)时红底白字