Files
QT_wuhan_YT/pages/chassispage.cpp
T
2026-09-09 17:00:37 +08:00

192 lines
6.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "chassispage.h"
#include "titlebar.h"
#include "statusstrip.h"
#include "alarmbanner.h"
#include "datacard.h"
#include "paramcontrol.h"
#include "udpcommunication.h"
#include "confirmdialog.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTimer>
#include "global.h"
ChassisPage::ChassisPage(AppContext* ctx, QWidget* parent)
: BasePage(ctx, parent)
{
QVBoxLayout* root = new QVBoxLayout(this);
root->setContentsMargins(0, 0, 0, 0);
root->setSpacing(0);
m_titleBar = new TitleBar(ctx, this);
m_titleBar->setTitle("机器人底盘");
root->addWidget(m_titleBar);
// 告警横幅(机械臂未回位 / 通信异常)
m_banner = new AlarmBanner(this);
root->addWidget(m_banner);
QHBoxLayout* main = new QHBoxLayout();
main->setContentsMargins(36, 16, 36, 16);
main->setSpacing(32);
// 左控制列(垂直居中 + 平均分布)
QWidget* left = new QWidget(this);
QVBoxLayout* leftLay = new QVBoxLayout(left);
leftLay->setContentsMargins(0, 0, 0, 0);
leftLay->setSpacing(8);
QPushButton* fwd = makeDirButton("前进", "fwd");
QPushButton* back = makeDirButton("后退", "back");
QPushButton* leftT = makeDirButton("左转向", "left");
QPushButton* rightT = makeDirButton("右转向", "right");
m_dirButtons << fwd << back << leftT << rightT;
leftLay->addStretch(1);
leftLay->addWidget(fwd);
leftLay->addStretch(1);
leftLay->addWidget(back);
leftLay->addStretch(1);
leftLay->addWidget(leftT);
leftLay->addStretch(1);
leftLay->addWidget(rightT);
leftLay->addStretch(1);
left->setFixedWidth(180);
main->addWidget(left);
// 中央卡片区(洗消/机械臂/气体检测仪)
QWidget* center = new QWidget(this);
QVBoxLayout* centerLay = new QVBoxLayout(center);
centerLay->setContentsMargins(0, 0, 0, 0);
centerLay->setSpacing(12);
m_washCard = new DataCard("洗消", center);
m_washCard->addField("A液位", "100L");
m_washCard->addField("泡沫液位", "30L");
m_armCard = new DataCard("机械臂", center);
m_armCard->addField("末端位置", "XYZ");
m_armCard->addField("姿态", "RX/RY/RZ");
m_gasCard = new DataCard("气体检测仪", center);
m_gasCard->addField("主机状态", "待机");
m_gasCard->addField("浓度", "0 ppb");
centerLay->addWidget(m_washCard, 1);
centerLay->addWidget(m_armCard, 1);
centerLay->addWidget(m_gasCard, 1);
main->addWidget(center, 1);
// 右参数区
QWidget* right = new QWidget(this);
QVBoxLayout* rightLay = new QVBoxLayout(right);
rightLay->setContentsMargins(0, 0, 0, 0);
rightLay->setSpacing(12);
m_chassisCard = new DataCard("底盘状态", right);
m_chassisCard->addField("电量SOC", "85%");
m_chassisCard->addField("电压U", "360V");
m_chassisCard->addField("车速V", "3.45 km/h");
m_chassisCard->addField("手刹", "有效");
m_chassisFieldFault = m_chassisCard->addField("故障", "无");
rightLay->addWidget(m_chassisCard, 1);
// 车速设置
double speed = ctx->getDouble(ctx->keySpeed(), 4.5);
m_speed = new ParamControl("车速设置", "km/h", 0.5, 0.0, 10.0, false, false, right);
m_speed->setValue(speed);
m_speed->setStyleSheet("background:transparent;");
connect(m_speed, &ParamControl::valueChanged, this, &ChassisPage::onSpeedChanged);
rightLay->addWidget(m_speed);
right->setFixedWidth(380);
main->addWidget(right);
root->addLayout(main, 1);
m_statusStrip = new StatusStrip(ctx, this);
connect(m_statusStrip, &StatusStrip::backClicked, this, [this]() { emit navigate(PageJob); });
root->addWidget(m_statusStrip);
// 车速自动保存(1s 防抖)
m_saveTimer = new QTimer(this);
m_saveTimer->setSingleShot(true);
m_saveTimer->setInterval(1000);
connect(m_saveTimer, &QTimer::timeout, this, &ChassisPage::onSpeedSaved);
connect(ctx->comm(), &UdpCommunication::telemetryUpdated, this, &ChassisPage::refresh);
connect(ctx, &AppContext::modeChanged, this, [this](Mode) { updateModeGating(); });
connect(ctx, &AppContext::estopChanged, this, [this](bool) { updateModeGating(); });
updateModeGating();
refresh();
}
QPushButton* ChassisPage::makeDirButton(const QString& text, const QString& dir)
{
QPushButton* b = button(text, "", this);
b->setFixedSize(180, 150);
b->setStyleSheet(QString("font-size:26px;background-color:%1;color:%2;border:1px solid %3;border-radius:12px;")
.arg(C::PANEL_HI, C::TEXT, C::BORDER));
connect(b, &QPushButton::pressed, this, [this, dir]() {
if (ctx()->mode != Mode::Drive) {
ConfirmDialog::toast(this, "请切换至行车模式");
return;
}
ctx()->comm()->sendChassisMove(dir, ctx()->getDouble(ctx()->keySpeed(), 4.5));
});
connect(b, &QPushButton::released, this, [this]() {
ctx()->comm()->sendChassisMove("stop", 0);
});
return b;
}
void ChassisPage::updateModeGating()
{
// 非行车模式或急停触发时禁用方向按钮
bool drive = (ctx()->mode == Mode::Drive) && !ctx()->estopTriggered;
for (QPushButton* b : m_dirButtons)
b->setEnabled(drive);
}
void ChassisPage::refresh()
{
const Telemetry& t = ctx()->telemetry;
// 机械臂未回位 / 通信异常告警
if (!t.commOk) {
m_banner->showAlarm("通信异常");
} else if (!t.armHomed && t.returnState != "idle") {
m_banner->showAlarm("机械臂未回位,请谨慎操作");
} else {
m_banner->clear();
}
m_chassisCard->setField(0, QString("%1%").arg(t.soc));
m_chassisCard->setField(1, QString("%1V").arg(t.volt, 0, 'f', 0));
m_chassisCard->setField(2, QString("%1 km/h").arg(t.speed, 0, 'f', 2));
m_chassisCard->setField(3, t.handbrake ? "有效" : "无效");
m_chassisCard->setField(m_chassisFieldFault, t.chassisFaults.isEmpty() ? "无" : t.chassisFaults.join(";"));
m_chassisCard->setAlarm(m_chassisFieldFault, !t.chassisFaults.isEmpty());
m_washCard->setField(0, QString("%1L").arg(t.levelA, 0, 'f', 0));
m_washCard->setField(1, QString("%1L").arg(t.levelFoam, 0, 'f', 0));
m_armCard->setField(0, t.pos);
m_armCard->setField(1, t.pose);
m_gasCard->setField(0, t.gasHost == "detecting" ? "检测中" : (t.gasHost == "fault" ? "故障" : "待机"));
m_gasCard->setField(1, QString("%1 ppb").arg(t.gasConc, 0, 'f', 0));
}
void ChassisPage::onSpeedChanged(double v)
{
// 1s 防抖后自动保存
m_saveTimer->start();
ctx()->comm()->sendSetParam(ctx()->keySpeed(), v);
}
void ChassisPage::onSpeedSaved()
{
ctx()->setDouble(ctx()->keySpeed(), m_speed->value());
ConfirmDialog::toast(this, "车速已保存");
}