#include "armpage.h" #include "titlebar.h" #include "statusstrip.h" #include "alarmbanner.h" #include "datacard.h" #include "udpcommunication.h" #include "confirmdialog.h" #include #include #include #include #include #include #include "global.h" ArmPage::ArmPage(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); // 左控制列(6 运动按钮 + 系统回位/暂停) QWidget* left = new QWidget(this); QVBoxLayout* leftLay = new QVBoxLayout(left); leftLay->setContentsMargins(0, 0, 0, 0); leftLay->setSpacing(8); auto addMove = [&](const QString& t, const QString& axis, int dir) { QPushButton* b = makeMoveButton(t, axis, dir); m_moveButtons << b; leftLay->addWidget(b); }; addMove("左平移", "x", -1); addMove("右平移", "x", +1); addMove("上升", "z", +1); addMove("下降", "z", -1); addMove("前平移", "y", +1); addMove("后平移", "y", -1); m_returnBtn = button("系统回位/暂停", "", left); m_returnBtn->setCheckable(true); m_returnBtn->setFixedSize(180, 90); m_returnBtn->setStyleSheet(QString("font-size:22px;background-color:%1;color:%2;border:1px solid %3;border-radius:12px;") .arg(C::PANEL_HI, C::TEXT, C::BORDER)); connect(m_returnBtn, &QPushButton::toggled, this, &ArmPage::onReturnToggled); leftLay->addWidget(m_returnBtn); m_returnStatus = label("", 18, C::TEXT_SUB, false, left); m_returnStatus->setAlignment(Qt::AlignCenter); m_returnStatus->setWordWrap(true); leftLay->addWidget(m_returnStatus); 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_chassisCard = new DataCard("底盘", center); m_chassisCard->addField("电量", "85%"); m_chassisCard->addField("电压", "360V"); m_chassisCard->addField("故障", "无"); m_washCard = new DataCard("洗消", center); m_washCard->addField("A液位", "100L"); m_washCard->addField("泡沫液位", "30L"); m_gasCard = new DataCard("气体检测仪", center); m_gasCard->addField("主机状态", "待机"); m_gasCard->addField("浓度", "0 ppb"); centerLay->addWidget(m_chassisCard, 1); centerLay->addWidget(m_washCard, 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_armCard = new DataCard("机械臂参数", right); m_armCard->addField("末端位置", "XYZ"); m_armCard->addField("姿态", "RX/RY/RZ"); m_armCard->addField("速度", "0"); m_armCard->addField("J1", "30°"); m_armCard->addField("J2", "20°"); m_armCard->addField("J3", "0°"); m_armCard->addField("J4", "90°"); m_armCard->addField("J5", "45°"); m_armCard->addField("J6", "0°"); rightLay->addWidget(m_armCard, 1); // 末端 6 姿态按钮(2 列 × 3 行) QGridLayout* endGrid = new QGridLayout(); endGrid->setSpacing(8); auto addEnd = [&](const QString& t, const QString& axis, int dir, int r, int c) { QPushButton* b = makeMoveButton(t, axis, dir); b->setFixedHeight(80); m_endButtons << b; endGrid->addWidget(b, r, c); }; addEnd("末端仰", "pitch", +1, 0, 0); addEnd("末端俯", "pitch", -1, 0, 1); addEnd("末端正偏航", "yaw", +1, 1, 0); addEnd("末端负偏航", "yaw", -1, 1, 1); addEnd("末端左横滚", "roll", -1, 2, 0); addEnd("末端右横滚", "roll", +1, 2, 1); rightLay->addLayout(endGrid); right->setFixedWidth(430); 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); m_statusTimer = new QTimer(this); m_statusTimer->setSingleShot(true); m_statusTimer->setInterval(3000); connect(m_statusTimer, &QTimer::timeout, this, [this]() { m_returnStatus->setText(""); }); connect(ctx->comm(), &UdpCommunication::telemetryUpdated, this, &ArmPage::refresh); connect(ctx, &AppContext::modeChanged, this, [this](Mode) { updateModeGating(); }); connect(ctx, &AppContext::estopChanged, this, [this](bool) { updateModeGating(); }); updateModeGating(); refresh(); } QPushButton* ArmPage::makeMoveButton(const QString& text, const QString& axis, int dir) { QPushButton* b = button(text, "", this); b->setFixedSize(180, 90); b->setStyleSheet(QString("font-size:24px;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, axis, dir]() { if (ctx()->mode != Mode::Arm) { ConfirmDialog::toast(this, "请切换至机械臂模式"); return; } ctx()->comm()->sendArmMove(axis, dir); }); connect(b, &QPushButton::released, this, [this, axis]() { ctx()->comm()->sendArmMove(axis, 0); }); return b; } void ArmPage::updateModeGating() { bool arm = (ctx()->mode == Mode::Arm) && !ctx()->estopTriggered; for (QPushButton* b : m_moveButtons) b->setEnabled(arm); for (QPushButton* b : m_endButtons) b->setEnabled(arm); } void ArmPage::onReturnToggled(bool on) { if (on) ctx()->comm()->sendArmReturn(); else ctx()->comm()->sendArmPause(); } void ArmPage::refresh() { const Telemetry& t = ctx()->telemetry; if (!t.commOk) { 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, t.chassisFaults.isEmpty() ? "无" : t.chassisFaults.join(";")); 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_gasCard->setField(0, t.gasHost == "detecting" ? "检测中" : (t.gasHost == "fault" ? "故障" : "待机")); m_gasCard->setField(1, QString("%1 ppb").arg(t.gasConc, 0, 'f', 0)); m_armCard->setField(0, t.pos); m_armCard->setField(1, t.pose); m_armCard->setField(2, QString("%1").arg(t.vel, 0, 'f', 1)); for (int i = 0; i < 6 && i < t.js.size(); ++i) m_armCard->setField(3 + i, QString("%1°").arg(t.js[i], 0, 'f', 0)); // 回位状态机 if (t.returnState != m_prevReturnState) { m_prevReturnState = t.returnState; if (t.returnState == "done") { m_returnBtn->setChecked(false); m_returnStatus->setText("机械臂系统完成回位"); m_returnStatus->setStyleSheet(QString("color:%1;font-size:22px;font-weight:700;").arg(C::SUCCESS)); m_statusTimer->start(); } else if (t.returnState == "fault") { m_returnBtn->setChecked(false); m_returnStatus->setText("机械臂系统回位异常"); m_returnStatus->setStyleSheet(QString("color:%1;font-size:22px;font-weight:700;").arg(C::DANGER)); } else if (t.returnState == "returning") { m_returnStatus->setText("回位中…"); m_returnStatus->setStyleSheet(QString("color:%1;font-size:22px;font-weight:700;").arg(C::WARNING)); } else { m_returnStatus->setText(""); } } }