diff --git a/src/Client/BattlefieldExplorationSystem.pro b/src/Client/BattlefieldExplorationSystem.pro index c78dc72a..dd428235 100644 --- a/src/Client/BattlefieldExplorationSystem.pro +++ b/src/Client/BattlefieldExplorationSystem.pro @@ -29,6 +29,7 @@ SOURCES += \ src/core/database/DatabaseHelper.cpp \ src/ui/main/MainWindow.cpp \ src/ui/dialogs/DeviceDialog.cpp \ + src/ui/dialogs/RobotDogControlDialog.cpp \ src/ui/components/DeviceCard.cpp \ src/ui/components/DeviceListPanel.cpp \ src/ui/components/SystemLogPanel.cpp \ @@ -47,6 +48,7 @@ HEADERS += \ include/core/database/DatabaseHelper.h \ include/ui/main/MainWindow.h \ include/ui/dialogs/DeviceDialog.h \ + include/ui/dialogs/RobotDogControlDialog.h \ include/ui/components/DeviceCard.h \ include/ui/components/DeviceListPanel.h \ include/ui/components/SystemLogPanel.h \ diff --git a/src/Client/include/ui/dialogs/RobotDogControlDialog.h b/src/Client/include/ui/dialogs/RobotDogControlDialog.h index 025ab1ed..144b1975 100644 --- a/src/Client/include/ui/dialogs/RobotDogControlDialog.h +++ b/src/Client/include/ui/dialogs/RobotDogControlDialog.h @@ -34,6 +34,11 @@ #include #include #include +#include +#include +#include +#include +#include /** * @class RobotDogControlDialog @@ -59,44 +64,34 @@ public: signals: /** - * @brief 开始自主建图信号 + * @brief 启动思岚雷达信号 */ - void startMapping(); + void startSlamRadar(); /** - * @brief 停止自主建图信号 + * @brief 停止思岚雷达信号 */ - void stopMapping(); + void stopSlamRadar(); /** - * @brief 开始导航避障信号 + * @brief 启动雷达建图信号 */ - void startNavigation(); + void startRadarMapping(); /** - * @brief 停止导航避障信号 + * @brief 停止雷达建图信号 */ - void stopNavigation(); + void stopRadarMapping(); /** - * @brief 开始照片传输信号 + * @brief 启动自动导航建图信号 */ - void startPhotoTransmission(); + void startAutoNavMapping(); /** - * @brief 停止照片传输信号 + * @brief 停止自动导航建图信号 */ - void stopPhotoTransmission(); - - /** - * @brief 开始人物识别信号 - */ - void startPersonRecognition(); - - /** - * @brief 停止人物识别信号 - */ - void stopPersonRecognition(); + void stopAutoNavMapping(); public slots: /** @@ -149,29 +144,24 @@ private slots: void onJumpClicked(); /** - * @brief 建图开关槽函数 - */ - void onMappingToggle(); - - /** - * @brief 导航开关槽函数 + * @brief 紧急停止槽函数 */ - void onNavigationToggle(); - + void onEmergencyStop(); + /** - * @brief 照片传输开关槽函数 + * @brief 思岚雷达开关槽函数 */ - void onPhotoTransmissionToggle(); + void onSlamRadarToggle(); /** - * @brief 人物识别开关槽函数 + * @brief 雷达建图开关槽函数 */ - void onPersonRecognitionToggle(); + void onRadarMappingToggle(); /** - * @brief 紧急停止槽函数 + * @brief 自动导航建图开关槽函数 */ - void onEmergencyStop(); + void onAutoNavMappingToggle(); private: /** @@ -224,12 +214,14 @@ private: // 任务控制模块 QGroupBox *m_missionControlGroup; - QPushButton *m_mappingBtn; - QPushButton *m_navigationBtn; - QPushButton *m_photoBtn; - QPushButton *m_recognitionBtn; + QPushButton *m_slamRadarBtn; + QPushButton *m_radarMappingBtn; + QPushButton *m_autoNavMappingBtn; QComboBox *m_missionModeCombo; + // 雷达显示组件 + QLabel *m_radarDisplayLabel; + // 状态监控模块 QGroupBox *m_statusGroup; QLabel *m_batteryLabel; @@ -241,15 +233,46 @@ private: QTextEdit *m_logTextEdit; // 状态变量 - bool m_isMappingActive; - bool m_isNavigationActive; - bool m_isPhotoTransmissionActive; - bool m_isPersonRecognitionActive; bool m_isMoving; QString m_currentPosture; + // 雷达状态变量 + bool m_isSlamRadarActive; + bool m_isRadarMappingActive; + bool m_isAutoNavMappingActive; + // 定时器 QTimer *m_statusUpdateTimer; + + // SSH连接和命令执行 + QProcess *m_sshProcess; + QString m_radarHost; + QString m_radarUser; + QString m_radarPassword; + + // 雷达建图进程(本地执行) + QProcess *m_radarMappingProcess; + + // 自动导航建图进程(本地执行) + QProcess *m_autoNavMappingProcess; + + // 私有方法 + void executeSlamRadarCommands(); + void stopSlamRadarProcess(); + void onSshProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onSshProcessError(QProcess::ProcessError error); + + // 雷达建图相关方法 + void executeRadarMappingCommands(); + void stopRadarMappingProcess(); + void onRadarMappingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onRadarMappingProcessError(QProcess::ProcessError error); + + // 自动导航建图相关方法 + void executeAutoNavMappingCommands(); + void stopAutoNavMappingProcess(); + void onAutoNavMappingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + void onAutoNavMappingProcessError(QProcess::ProcessError error); }; #endif // ROBOTDOGCONTROLDIALOG_H diff --git a/src/Client/include/ui/main/MainWindow.h b/src/Client/include/ui/main/MainWindow.h index 23e41920..fe7d49f9 100644 --- a/src/Client/include/ui/main/MainWindow.h +++ b/src/Client/include/ui/main/MainWindow.h @@ -44,8 +44,9 @@ #include "ui/components/DeviceListPanel.h" #include "ui/components/SystemLogPanel.h" #include "ui/components/RightFunctionPanel.h" -// #include "ui/dialogs/DroneControlDialog.h" -// #include "ui/dialogs/RobotDogControlDialog.h" +#include "ui/dialogs/DeviceDialog.h" +#include "ui/dialogs/RobotDogControlDialog.h" +#include "ui/components/DeviceCard.h" // 标准库头文件 #include @@ -357,9 +358,8 @@ private: QVector> m_robotList; ///< 机器人列表(名称-IP地址对) QVector> m_uavList; ///< 无人机列表(名称-IP地址对) - // 控制对话框(暂时注释掉以避免编译问题) - // DroneControlDialog *m_droneControlDialog; ///< 无人机控制对话框 - // RobotDogControlDialog *m_robotDogControlDialog; ///< 机器狗控制对话框 + // 控制对话框 + RobotDogControlDialog *m_robotDogControlDialog; ///< 机器狗控制对话框 // 人脸识别相关成员变量已移除(功能暂未实现) }; diff --git a/src/Client/src/ui/components/RightFunctionPanel.cpp b/src/Client/src/ui/components/RightFunctionPanel.cpp index d934c2d5..073fb984 100644 --- a/src/Client/src/ui/components/RightFunctionPanel.cpp +++ b/src/Client/src/ui/components/RightFunctionPanel.cpp @@ -214,7 +214,7 @@ void RightFunctionPanel::setupBattlefieldExplorationModule() m_explorationCard = new ModuleCard("🎯 战场探索", "🎯", this); m_explorationCard->setObjectName("ModuleCard"); m_explorationCard->setProperty("data-module", "battlefield"); - + // 简化设计:只显示两个主要功能入口按钮 QWidget *mainControlWidget = new QWidget(); mainControlWidget->setObjectName("main-control-widget"); @@ -956,14 +956,14 @@ void RightFunctionPanel::onRobotDogControlClicked() void RightFunctionPanel::onAIAnalysis() { emit requestAIAnalysis(); - + // 显示分析状态 m_aiAnalysisBtn->setText("🧠 分析中..."); m_aiAnalysisBtn->setProperty("class", "loading"); m_aiAnalysisBtn->setEnabled(false); m_aiAnalysisBtn->style()->unpolish(m_aiAnalysisBtn); m_aiAnalysisBtn->style()->polish(m_aiAnalysisBtn); - + QTimer::singleShot(3000, [this]() { m_aiAnalysisBtn->setText("🤖 AI分析"); m_aiAnalysisBtn->setProperty("class", "secondary-medium"); @@ -1020,21 +1020,21 @@ void RightFunctionPanel::updateDeviceStatus(const QString &deviceName, bool onli } else { deviceType = "未知设备"; } - + QString statusMsg; - if (online) { - if (battery > 80) { + if (online) { + if (battery > 80) { statusMsg = QString("%1 %2: 📶 连接质量 %3% (优秀)").arg(deviceType).arg(deviceName).arg(battery); - } else if (battery > 50) { + } else if (battery > 50) { statusMsg = QString("%1 %2: 📶 连接质量 %3% (良好)").arg(deviceType).arg(deviceName).arg(battery); - } else if (battery > 20) { + } else if (battery > 20) { statusMsg = QString("%1 %2: ⚠️ 连接质量 %3% (一般)").arg(deviceType).arg(deviceName).arg(battery); - } else { + } else { statusMsg = QString("%1 %2: ⚠️ 连接质量 %3% (较差)").arg(deviceType).arg(deviceName).arg(battery); - } - } else { + } + } else { statusMsg = QString("%1 %2: ❌ 设备离线").arg(deviceType).arg(deviceName); - } + } SystemLogger::getInstance()->logInfo(statusMsg); } diff --git a/src/Client/src/ui/dialogs/RobotDogControlDialog.cpp b/src/Client/src/ui/dialogs/RobotDogControlDialog.cpp index 1781c85c..232ee8d0 100644 --- a/src/Client/src/ui/dialogs/RobotDogControlDialog.cpp +++ b/src/Client/src/ui/dialogs/RobotDogControlDialog.cpp @@ -13,18 +13,26 @@ #include #include #include +#include +#include +#include RobotDogControlDialog::RobotDogControlDialog(QWidget *parent) : QDialog(parent) , m_mainLayout(nullptr) , m_contentLayout(nullptr) - , m_isMappingActive(false) - , m_isNavigationActive(false) - , m_isPhotoTransmissionActive(false) - , m_isPersonRecognitionActive(false) , m_isMoving(false) , m_currentPosture("站立") + , m_isSlamRadarActive(false) + , m_isRadarMappingActive(false) + , m_isAutoNavMappingActive(false) , m_statusUpdateTimer(new QTimer(this)) + , m_sshProcess(new QProcess(this)) + , m_radarHost("192.168.123.15") + , m_radarUser("unitree") + , m_radarPassword("123") + , m_radarMappingProcess(new QProcess(this)) + , m_autoNavMappingProcess(new QProcess(this)) { setupUI(); applyStyles(); @@ -32,6 +40,24 @@ RobotDogControlDialog::RobotDogControlDialog(QWidget *parent) // 启动状态更新定时器 m_statusUpdateTimer->start(1000); + + // 连接SSH进程信号 + connect(m_sshProcess, QOverload::of(&QProcess::finished), + this, &RobotDogControlDialog::onSshProcessFinished); + connect(m_sshProcess, &QProcess::errorOccurred, + this, &RobotDogControlDialog::onSshProcessError); + + // 连接雷达建图进程信号 + connect(m_radarMappingProcess, QOverload::of(&QProcess::finished), + this, &RobotDogControlDialog::onRadarMappingProcessFinished); + connect(m_radarMappingProcess, &QProcess::errorOccurred, + this, &RobotDogControlDialog::onRadarMappingProcessError); + + // 连接自动导航建图进程信号 + connect(m_autoNavMappingProcess, QOverload::of(&QProcess::finished), + this, &RobotDogControlDialog::onAutoNavMappingProcessFinished); + connect(m_autoNavMappingProcess, &QProcess::errorOccurred, + this, &RobotDogControlDialog::onAutoNavMappingProcessError); } RobotDogControlDialog::~RobotDogControlDialog() @@ -45,8 +71,8 @@ void RobotDogControlDialog::setupUI() { setWindowTitle("🐕 机器狗控制中心"); setModal(false); - setMinimumSize(900, 700); - resize(1000, 750); + setMinimumSize(1700, 1100); // 从1600增加到1700以适应新布局 + resize(1900, 1800); // 从1800增加到1900 // 窗口居中显示 QRect screenGeometry = QApplication::desktop()->screenGeometry(); @@ -55,26 +81,26 @@ void RobotDogControlDialog::setupUI() move(x, y); m_mainLayout = new QVBoxLayout(this); - m_mainLayout->setSpacing(20); - m_mainLayout->setContentsMargins(20, 20, 20, 20); + m_mainLayout->setSpacing(35); + m_mainLayout->setContentsMargins(35, 35, 35, 35); // 标题 QLabel *titleLabel = new QLabel("🐕 机器狗控制中心"); titleLabel->setObjectName("DialogTitle"); titleLabel->setAlignment(Qt::AlignCenter); titleLabel->setStyleSheet( - "font-size: 24px; " + "font-size: 32px; " "font-weight: bold; " "color: #16a085; " - "padding: 10px; " - "border-bottom: 2px solid #16a085; " - "margin-bottom: 10px;" + "padding: 20px; " + "border-bottom: 4px solid #16a085; " + "margin-bottom: 20px;" ); m_mainLayout->addWidget(titleLabel); // 主内容区域 m_contentLayout = new QHBoxLayout(); - m_contentLayout->setSpacing(20); + m_contentLayout->setSpacing(40); setupMovementControlModule(); setupMissionControlModule(); @@ -88,7 +114,7 @@ void RobotDogControlDialog::setupUI() QPushButton *closeBtn = new QPushButton("关闭"); closeBtn->setObjectName("CloseBtn"); - closeBtn->setMinimumSize(100, 40); + closeBtn->setMinimumSize(150, 60); connect(closeBtn, &QPushButton::clicked, this, &QDialog::close); buttonLayout->addWidget(closeBtn); @@ -98,35 +124,129 @@ void RobotDogControlDialog::setupUI() void RobotDogControlDialog::setupMovementControlModule() { m_movementControlGroup = new QGroupBox("🎮 运动控制"); - m_movementControlGroup->setObjectName("ControlGroup"); - m_movementControlGroup->setMinimumWidth(280); + m_movementControlGroup->setObjectName("MovementControlGroup"); + m_movementControlGroup->setMinimumWidth(420); // 从580减少到420 + m_movementControlGroup->setMaximumWidth(480); // 设置最大宽度限制 + m_movementControlGroup->setStyleSheet( + "QGroupBox#MovementControlGroup {" + " font-size: 20px;" + " font-weight: bold;" + " color: #2c3e50;" + " border: 3px solid #3498db;" + " border-radius: 25px;" + " margin-top: 20px;" + " padding-top: 25px;" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 #ffffff, stop:0.1 #f8f9fa, stop:1 #ecf0f1);" + "}" + "QGroupBox#MovementControlGroup::title {" + " subcontrol-origin: margin;" + " left: 20px;" + " padding: 10px 20px 10px 20px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #3498db, stop:0.5 #2980b9, stop:1 #1abc9c);" + " color: white;" + " border-radius: 12px;" + " font-size: 18px;" + " font-weight: bold;" + " border: 2px solid #2980b9;" + "}" + ); QVBoxLayout *movementLayout = new QVBoxLayout(m_movementControlGroup); - movementLayout->setSpacing(15); + movementLayout->setSpacing(25); + movementLayout->setContentsMargins(25, 35, 25, 25); + + // 方向控制区域 - 优化为紧凑设计 + QWidget *directionWidget = new QWidget(); + directionWidget->setObjectName("DirectionControlWidget"); + directionWidget->setMinimumSize(420, 320); // 调整外层容器尺寸 + directionWidget->setMaximumSize(480, 360); + directionWidget->setStyleSheet( + "QWidget#DirectionControlWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #ffffff, stop:0.3 #f8f9fa, stop:1 #ecf0f1);" + " border: 3px solid #3498db;" + " border-radius: 20px;" + " padding: 15px;" // 减少内边距 + " margin: 5px;" + "}" + ); + + QVBoxLayout *directionMainLayout = new QVBoxLayout(directionWidget); + directionMainLayout->setSpacing(10); // 减少间距 + + // 方向控制标题 - 简化设计 + QLabel *directionTitle = new QLabel("🕹️ 方向控制"); + directionTitle->setObjectName("SectionTitle"); + directionTitle->setStyleSheet( + "QLabel#SectionTitle {" + " font-size: 16px;" + " font-weight: bold;" + " color: #2c3e50;" + " padding: 8px 0px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(52, 152, 219, 0.15), stop:1 rgba(26, 188, 156, 0.15));" + " border: 2px solid #3498db;" + " border-radius: 12px;" + " margin-bottom: 10px;" + "}" + ); + directionTitle->setAlignment(Qt::AlignCenter); + directionMainLayout->addWidget(directionTitle); + + // 按钮容器 - 调整尺寸以更好地贴合外层容器 + QWidget *buttonContainer = new QWidget(); + buttonContainer->setMinimumSize(400, 200); // 增加尺寸以更好地填充 + buttonContainer->setMaximumSize(450, 240); + buttonContainer->setStyleSheet( + "QWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 rgba(255,255,255,0.9), stop:1 rgba(236,240,241,0.9));" + " border-radius: 12px;" + " padding: 8px;" // 减少内边距从15px到8px + "}" + ); - // 方向控制按钮 - 十字布局 - QGridLayout *directionLayout = new QGridLayout(); - directionLayout->setSpacing(10); + QGridLayout *directionLayout = new QGridLayout(buttonContainer); + directionLayout->setSpacing(15); // 增加按钮间距 + directionLayout->setContentsMargins(10, 10, 10, 10); // 增加边距以更好地填充 - m_forwardBtn = new QPushButton("⬆️ 前进"); - m_forwardBtn->setObjectName("DirectionBtn"); - m_forwardBtn->setMinimumHeight(50); + // 创建方向控制按钮 - 调整尺寸以更好地填充容器 + m_forwardBtn = new QPushButton(); + m_forwardBtn->setObjectName("ModernDirectionBtn"); + m_forwardBtn->setText("↑\n前进"); + m_forwardBtn->setMinimumSize(55, 55); // 增加按钮尺寸 + m_forwardBtn->setMaximumSize(55, 55); + m_forwardBtn->setToolTip("前进移动"); - m_backwardBtn = new QPushButton("⬇️ 后退"); - m_backwardBtn->setObjectName("DirectionBtn"); - m_backwardBtn->setMinimumHeight(50); + m_backwardBtn = new QPushButton(); + m_backwardBtn->setObjectName("ModernDirectionBtn"); + m_backwardBtn->setText("↓\n后退"); + m_backwardBtn->setMinimumSize(55, 55); + m_backwardBtn->setMaximumSize(55, 55); + m_backwardBtn->setToolTip("后退移动"); - m_leftBtn = new QPushButton("⬅️ 左转"); - m_leftBtn->setObjectName("DirectionBtn"); - m_leftBtn->setMinimumHeight(50); + m_leftBtn = new QPushButton(); + m_leftBtn->setObjectName("ModernDirectionBtn"); + m_leftBtn->setText("←\n左转"); + m_leftBtn->setMinimumSize(55, 55); + m_leftBtn->setMaximumSize(55, 55); + m_leftBtn->setToolTip("向左转向"); - m_rightBtn = new QPushButton("➡️ 右转"); - m_rightBtn->setObjectName("DirectionBtn"); - m_rightBtn->setMinimumHeight(50); + m_rightBtn = new QPushButton(); + m_rightBtn->setObjectName("ModernDirectionBtn"); + m_rightBtn->setText("→\n右转"); + m_rightBtn->setMinimumSize(55, 55); + m_rightBtn->setMaximumSize(55, 55); + m_rightBtn->setToolTip("向右转向"); - m_stopBtn = new QPushButton("⏹️ 停止"); - m_stopBtn->setObjectName("StopBtn"); - m_stopBtn->setMinimumHeight(50); + m_stopBtn = new QPushButton(); + m_stopBtn->setObjectName("ModernStopBtn"); + m_stopBtn->setText("■\n停止"); + m_stopBtn->setMinimumSize(55, 55); + m_stopBtn->setMaximumSize(55, 55); + m_stopBtn->setToolTip("立即停止"); // 十字布局 directionLayout->addWidget(m_forwardBtn, 0, 1); @@ -135,58 +255,196 @@ void RobotDogControlDialog::setupMovementControlModule() directionLayout->addWidget(m_rightBtn, 1, 2); directionLayout->addWidget(m_backwardBtn, 2, 1); - movementLayout->addLayout(directionLayout); + // 设置行列拉伸 + directionLayout->setRowStretch(0, 1); + directionLayout->setRowStretch(1, 1); + directionLayout->setRowStretch(2, 1); + directionLayout->setColumnStretch(0, 1); + directionLayout->setColumnStretch(1, 1); + directionLayout->setColumnStretch(2, 1); - // 姿态控制按钮 - QLabel *postureLabel = new QLabel("姿态控制:"); - movementLayout->addWidget(postureLabel); + directionMainLayout->addWidget(buttonContainer, 0, Qt::AlignCenter); + movementLayout->addWidget(directionWidget); - QHBoxLayout *postureLayout = new QHBoxLayout(); - postureLayout->setSpacing(10); + // 姿态控制区域 - 优化为垂直布局 + QWidget *postureWidget = new QWidget(); + postureWidget->setObjectName("PostureControlWidget"); + postureWidget->setStyleSheet( + "QWidget#PostureControlWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #ffffff, stop:0.3 #f8f9fa, stop:1 #ecf0f1);" + " border: 3px solid #27ae60;" + " border-radius: 20px;" + " padding: 20px;" + " margin: 5px;" + "}" + ); + + QVBoxLayout *postureMainLayout = new QVBoxLayout(postureWidget); + postureMainLayout->setSpacing(15); + + QLabel *postureTitle = new QLabel("🤖 姿态控制"); + postureTitle->setObjectName("SectionTitle"); + postureTitle->setStyleSheet( + "QLabel#SectionTitle {" + " font-size: 16px;" + " font-weight: bold;" + " color: #2c3e50;" + " padding: 8px 0px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(39, 174, 96, 0.15), stop:1 rgba(46, 204, 113, 0.15));" + " border: 2px solid #27ae60;" + " border-radius: 12px;" + " margin-bottom: 10px;" + "}" + ); + postureTitle->setAlignment(Qt::AlignCenter); + postureMainLayout->addWidget(postureTitle); + + // 姿态按钮 - 垂直排列以节省空间 + m_standBtn = new QPushButton(); + m_standBtn->setObjectName("ModernPostureBtn"); + m_standBtn->setText("🧍 站立"); + m_standBtn->setMinimumHeight(50); + m_standBtn->setToolTip("切换到站立姿态"); + + m_lieDownBtn = new QPushButton(); + m_lieDownBtn->setObjectName("ModernPostureBtn"); + m_lieDownBtn->setText("🛌 趴下"); + m_lieDownBtn->setMinimumHeight(50); + m_lieDownBtn->setToolTip("切换到趴下姿态"); + + m_jumpBtn = new QPushButton(); + m_jumpBtn->setObjectName("ModernPostureBtn"); + m_jumpBtn->setText("🦘 跳跃"); + m_jumpBtn->setMinimumHeight(50); + m_jumpBtn->setToolTip("执行跳跃动作"); - m_standBtn = new QPushButton("🧍 站立"); - m_standBtn->setObjectName("PostureBtn"); - m_standBtn->setMinimumHeight(45); + postureMainLayout->addWidget(m_standBtn); + postureMainLayout->addWidget(m_lieDownBtn); + postureMainLayout->addWidget(m_jumpBtn); - m_lieDownBtn = new QPushButton("🛌 趴下"); - m_lieDownBtn->setObjectName("PostureBtn"); - m_lieDownBtn->setMinimumHeight(45); + movementLayout->addWidget(postureWidget); - m_jumpBtn = new QPushButton("🦘 跳跃"); - m_jumpBtn->setObjectName("PostureBtn"); - m_jumpBtn->setMinimumHeight(45); + // 速度控制区域 - 更紧凑的设计 + QWidget *speedWidget = new QWidget(); + speedWidget->setObjectName("SpeedControlWidget"); + speedWidget->setStyleSheet( + "QWidget#SpeedControlWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #ffffff, stop:0.3 #f8f9fa, stop:1 #ecf0f1);" + " border: 2px solid #f39c12;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + "}" + ); - postureLayout->addWidget(m_standBtn); - postureLayout->addWidget(m_lieDownBtn); - postureLayout->addWidget(m_jumpBtn); - movementLayout->addLayout(postureLayout); + QVBoxLayout *speedLayout = new QVBoxLayout(speedWidget); + speedLayout->setSpacing(10); + + QLabel *speedTitle = new QLabel("⚡ 速度"); + speedTitle->setObjectName("SectionTitle"); + speedTitle->setStyleSheet( + "QLabel#SectionTitle {" + " font-size: 14px;" + " font-weight: bold;" + " color: #2c3e50;" + " padding: 6px 0px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(243, 156, 18, 0.15), stop:1 rgba(230, 126, 34, 0.15));" + " border: 2px solid #f39c12;" + " border-radius: 10px;" + " margin-bottom: 8px;" + "}" + ); + speedTitle->setAlignment(Qt::AlignCenter); + speedLayout->addWidget(speedTitle); + + // 紧凑的速度控制 + QHBoxLayout *speedControlLayout = new QHBoxLayout(); + speedControlLayout->setSpacing(8); - // 速度控制 - QLabel *speedLabel = new QLabel("移动速度:"); m_speedSlider = new QSlider(Qt::Horizontal); + m_speedSlider->setObjectName("ModernSpeedSlider"); m_speedSlider->setRange(1, 10); m_speedSlider->setValue(5); + m_speedSlider->setMinimumHeight(25); + m_speedSlider->setStyleSheet( + "QSlider#ModernSpeedSlider::groove:horizontal {" + " border: 2px solid #d35400;" + " height: 8px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #f39c12, stop:1 #d35400);" + " margin: 2px 0;" + " border-radius: 4px;" + "}" + "QSlider#ModernSpeedSlider::handle:horizontal {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #ffffff, stop:1 #bdc3c7);" + " border: 2px solid #2c3e50;" + " width: 16px;" + " height: 16px;" + " margin: -4px 0;" + " border-radius: 8px;" + "}" + ); + + QLabel *speedValueLabel = new QLabel("5"); + speedValueLabel->setObjectName("SpeedValueLabel"); + speedValueLabel->setStyleSheet( + "QLabel#SpeedValueLabel {" + " font-size: 14px;" + " font-weight: bold;" + " color: #d35400;" + " background: rgba(243, 156, 18, 0.2);" + " border: 2px solid #e67e22;" + " border-radius: 6px;" + " padding: 3px 8px;" + " min-width: 25px;" + "}" + ); + speedValueLabel->setAlignment(Qt::AlignCenter); + + // 连接速度滑块值变化 + connect(m_speedSlider, &QSlider::valueChanged, [speedValueLabel](int value) { + speedValueLabel->setText(QString("%1").arg(value)); + }); + + speedControlLayout->addWidget(m_speedSlider); + speedControlLayout->addWidget(speedValueLabel); - movementLayout->addWidget(speedLabel); - movementLayout->addWidget(m_speedSlider); + speedLayout->addLayout(speedControlLayout); + movementLayout->addWidget(speedWidget); - // 紧急停止按钮 + // 紧急停止按钮 - 优化尺寸 m_emergencyStopBtn = new QPushButton("🚨 紧急停止"); - m_emergencyStopBtn->setObjectName("DangerBtn"); + m_emergencyStopBtn->setObjectName("ModernEmergencyBtn"); m_emergencyStopBtn->setMinimumHeight(60); m_emergencyStopBtn->setStyleSheet( - "QPushButton {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #e74c3c, stop:1 #c0392b);" + "QPushButton#ModernEmergencyBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #e74c3c, stop:0.5 #c0392b, stop:1 #a93226);" " color: white;" " font-size: 16px;" " font-weight: bold;" - " border: 2px solid #e74c3c;" - " border-radius: 8px;" + " border: 3px solid #a93226;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 10px 5px;" + "}" + "QPushButton#ModernEmergencyBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ec7063, stop:0.5 #e74c3c, stop:1 #c0392b);" + " border: 3px solid #c0392b;" + " transform: translateY(-2px);" "}" - "QPushButton:hover {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #c0392b, stop:1 #a93226);" + "QPushButton#ModernEmergencyBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #c0392b, stop:0.5 #a93226, stop:1 #922b21);" + " border: 3px solid #922b21;" + " transform: translateY(0px);" "}" ); @@ -199,46 +457,225 @@ void RobotDogControlDialog::setupMovementControlModule() void RobotDogControlDialog::setupMissionControlModule() { m_missionControlGroup = new QGroupBox("🎯 任务控制"); - m_missionControlGroup->setObjectName("ControlGroup"); - m_missionControlGroup->setMinimumWidth(280); + m_missionControlGroup->setObjectName("MissionControlGroup"); + m_missionControlGroup->setMinimumWidth(720); // 从520增加到720 + m_missionControlGroup->setMaximumWidth(800); // 设置最大宽度限制 + m_missionControlGroup->setStyleSheet( + "QGroupBox#MissionControlGroup {" + " font-size: 20px;" + " font-weight: bold;" + " color: #2c3e50;" + " border: 3px solid #8e44ad;" + " border-radius: 25px;" + " margin-top: 20px;" + " padding-top: 25px;" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 #ffffff, stop:0.1 #f8f9fa, stop:1 #ecf0f1);" + "}" + "QGroupBox#MissionControlGroup::title {" + " subcontrol-origin: margin;" + " left: 20px;" + " padding: 10px 20px 10px 20px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #8e44ad, stop:0.5 #9b59b6, stop:1 #e74c3c);" + " color: white;" + " border-radius: 12px;" + " font-size: 18px;" + " font-weight: bold;" + " border: 2px solid #8e44ad;" + "}" + ); QVBoxLayout *missionLayout = new QVBoxLayout(m_missionControlGroup); - missionLayout->setSpacing(15); - - // 任务模式选择 - QLabel *modeLabel = new QLabel("任务模式:"); - m_missionModeCombo = new QComboBox(); - m_missionModeCombo->addItems({"手动控制", "自主巡逻", "目标跟踪", "区域探索", "护卫模式"}); - m_missionModeCombo->setMinimumHeight(35); - - missionLayout->addWidget(modeLabel); - missionLayout->addWidget(m_missionModeCombo); - - // 功能控制按钮 - m_mappingBtn = new QPushButton("🗺️ 开始建图"); - m_mappingBtn->setObjectName("FunctionBtn"); - m_mappingBtn->setMinimumHeight(50); - m_mappingBtn->setCheckable(true); - - m_navigationBtn = new QPushButton("🧭 导航避障"); - m_navigationBtn->setObjectName("FunctionBtn"); - m_navigationBtn->setMinimumHeight(50); - m_navigationBtn->setCheckable(true); - - m_photoBtn = new QPushButton("📸 照片传输"); - m_photoBtn->setObjectName("FunctionBtn"); - m_photoBtn->setMinimumHeight(50); - m_photoBtn->setCheckable(true); - - m_recognitionBtn = new QPushButton("👁️ 人物识别"); - m_recognitionBtn->setObjectName("FunctionBtn"); - m_recognitionBtn->setMinimumHeight(50); - m_recognitionBtn->setCheckable(true); - - missionLayout->addWidget(m_mappingBtn); - missionLayout->addWidget(m_navigationBtn); - missionLayout->addWidget(m_photoBtn); - missionLayout->addWidget(m_recognitionBtn); + missionLayout->setSpacing(15); // 从30减少到15以缩小按钮间距 + missionLayout->setContentsMargins(40, 40, 40, 40); + + + // 思岚雷达控制按钮 + m_slamRadarBtn = new QPushButton("🌐 启动思岚雷达"); + m_slamRadarBtn->setObjectName("FunctionBtn"); + m_slamRadarBtn->setMinimumHeight(50); // 从80减少到50 + m_slamRadarBtn->setCheckable(true); + m_slamRadarBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 雷达建图按钮 + m_radarMappingBtn = new QPushButton("🗺️ 启动雷达建图"); + m_radarMappingBtn->setObjectName("FunctionBtn"); + m_radarMappingBtn->setMinimumHeight(50); // 从80减少到50 + m_radarMappingBtn->setCheckable(true); + m_radarMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + "QPushButton#FunctionBtn:checked {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #e91e63, stop:1 #c2185b);" + " border: 3px solid #c2185b;" + "}" + ); + + // 自动导航建图按钮 + m_autoNavMappingBtn = new QPushButton("🧭 启动自动导航建图"); + m_autoNavMappingBtn->setObjectName("FunctionBtn"); + m_autoNavMappingBtn->setMinimumHeight(50); // 从80减少到50 + m_autoNavMappingBtn->setCheckable(true); + m_autoNavMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + "QPushButton#FunctionBtn:checked {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #e91e63, stop:1 #c2185b);" + " border: 3px solid #c2185b;" + "}" + ); + + missionLayout->addWidget(m_slamRadarBtn); + missionLayout->addWidget(m_radarMappingBtn); + missionLayout->addWidget(m_autoNavMappingBtn); + + // 雷达图显示区域 + QWidget *radarDisplayWidget = new QWidget(); + radarDisplayWidget->setObjectName("RadarDisplayWidget"); + radarDisplayWidget->setMinimumHeight(750); // 从700增加到750以进一步增加雷达显示区域 + radarDisplayWidget->setStyleSheet( + "QWidget#RadarDisplayWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 20px;" + " padding: 15px;" // 从20减少到15 + " margin: 10px 5px;" + "}" + ); + + QVBoxLayout *radarLayout = new QVBoxLayout(radarDisplayWidget); + radarLayout->setSpacing(10); // 从20减少到10 + radarLayout->setContentsMargins(15, 15, 15, 15); // 从20减少到15 + + // 雷达显示标题 - 减少高度 + QLabel *radarTitle = new QLabel("📡 雷达图显示"); + radarTitle->setObjectName("RadarTitle"); + radarTitle->setStyleSheet( + "QLabel#RadarTitle {" + " font-size: 16px;" // 从20减少到16 + " font-weight: bold;" + " color: #ffffff;" // 改为白色以适应深色背景 + " padding: 8px 0px;" // 从12减少到8 + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(255, 255, 255, 0.1), stop:1 rgba(255, 255, 255, 0.05));" + " border: 2px solid #34495e;" // 从3px减少到2px + " border-radius: 10px;" // 从15减少到10 + " margin-bottom: 8px;" // 从15减少到8 + "}" + ); + radarTitle->setAlignment(Qt::AlignCenter); + radarLayout->addWidget(radarTitle); + + // 雷达图显示区域 - 增加尺寸 + m_radarDisplayLabel = new QLabel(); + m_radarDisplayLabel->setObjectName("RadarDisplay"); + m_radarDisplayLabel->setMinimumSize(580, 520); // 从460增加到520 + m_radarDisplayLabel->setMaximumSize(640, 540); // 从480增加到540 + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + m_radarDisplayLabel->setAlignment(Qt::AlignCenter); + m_radarDisplayLabel->setScaledContents(true); + + // 初始显示雷达待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + m_radarDisplayLabel->styleSheet() + + "color: #bdc3c7; font-size: 16px; font-weight: bold;" + ); + + radarLayout->addWidget(m_radarDisplayLabel, 0, Qt::AlignCenter); + + missionLayout->addWidget(radarDisplayWidget); missionLayout->addStretch(); m_contentLayout->addWidget(m_missionControlGroup); @@ -247,57 +684,282 @@ void RobotDogControlDialog::setupMissionControlModule() void RobotDogControlDialog::setupStatusMonitorModule() { m_statusGroup = new QGroupBox("📊 状态监控"); - m_statusGroup->setObjectName("ControlGroup"); - m_statusGroup->setMinimumWidth(320); + m_statusGroup->setObjectName("StatusMonitorGroup"); + m_statusGroup->setMinimumWidth(420); // 从520减少到420 + m_statusGroup->setMaximumWidth(480); // 设置最大宽度限制 + m_statusGroup->setStyleSheet( + "QGroupBox#StatusMonitorGroup {" + " font-size: 20px;" + " font-weight: bold;" + " color: #2c3e50;" + " border: 3px solid #8e44ad;" + " border-radius: 25px;" + " margin-top: 20px;" + " padding-top: 25px;" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 #ffffff, stop:0.1 #f8f9fa, stop:1 #ecf0f1);" + "}" + "QGroupBox#StatusMonitorGroup::title {" + " subcontrol-origin: margin;" + " left: 20px;" + " padding: 10px 20px 10px 20px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #8e44ad, stop:0.5 #9b59b6, stop:1 #e74c3c);" + " color: white;" + " border-radius: 12px;" + " font-size: 18px;" + " font-weight: bold;" + " border: 2px solid #8e44ad;" + "}" + ); QVBoxLayout *statusLayout = new QVBoxLayout(m_statusGroup); - statusLayout->setSpacing(15); + statusLayout->setSpacing(20); + statusLayout->setContentsMargins(25, 35, 25, 25); - // 电池状态 - QHBoxLayout *batteryLayout = new QHBoxLayout(); - m_batteryLabel = new QLabel("电池电量:"); + // 电池状态 - 优化布局 + QWidget *batteryWidget = new QWidget(); + batteryWidget->setObjectName("BatteryWidget"); + batteryWidget->setStyleSheet( + "QWidget#BatteryWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #ffffff, stop:0.3 #f8f9fa, stop:1 #ecf0f1);" + " border: 3px solid #27ae60;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + "}" + ); + + QVBoxLayout *batteryLayout = new QVBoxLayout(batteryWidget); + batteryLayout->setSpacing(8); + + m_batteryLabel = new QLabel("🔋 电池电量"); + m_batteryLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #2c3e50; " // 减少字体大小并确保颜色对比度 + "background: rgba(39, 174, 96, 0.15); border: 2px solid #27ae60; " // 减少背景透明度 + "border-radius: 8px; padding: 5px 10px;" // 减少内边距 + ); + m_batteryLabel->setAlignment(Qt::AlignCenter); + m_batteryProgress = new QProgressBar(); m_batteryProgress->setRange(0, 100); m_batteryProgress->setValue(90); m_batteryProgress->setTextVisible(true); m_batteryProgress->setFormat("%p%"); + m_batteryProgress->setMinimumHeight(35); + m_batteryProgress->setStyleSheet( + "QProgressBar {" + " border: 3px solid #27ae60;" + " border-radius: 12px;" + " text-align: center;" + " font-size: 14px;" + " font-weight: bold;" + " color: white;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #ecf0f1, stop:1 #bdc3c7);" + "}" + "QProgressBar::chunk {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #27ae60, stop:0.5 #2ecc71, stop:1 #58d68d);" + " border-radius: 10px;" + " margin: 2px;" + "}" + ); batteryLayout->addWidget(m_batteryLabel); batteryLayout->addWidget(m_batteryProgress); - statusLayout->addLayout(batteryLayout); + statusLayout->addWidget(batteryWidget); - // 运行参数 + // 运行参数 - 优化为更紧凑的网格布局 + QWidget *paramWidget = new QWidget(); + paramWidget->setObjectName("ParamWidget"); + paramWidget->setStyleSheet( + "QWidget#ParamWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 rgba(255,255,255,0.9), stop:1 rgba(236,240,241,0.9));" + " border: 3px solid #3498db;" + " border-radius: 20px;" + " padding: 20px;" + " margin: 5px;" + "}" + ); + + QVBoxLayout *paramMainLayout = new QVBoxLayout(paramWidget); + paramMainLayout->setSpacing(15); + + // 参数标题 + QLabel *paramTitle = new QLabel("📈 运行参数"); + paramTitle->setStyleSheet( + "font-size: 16px; font-weight: bold; color: #2c3e50; " // 修改字体颜色为深色以避免与背景重合 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(52, 152, 219, 0.2), stop:1 rgba(41, 128, 185, 0.2));" // 增加背景透明度 + "border: 2px solid #3498db; border-radius: 10px; " + "padding: 6px 0px; margin-bottom: 10px;" // 减少内边距 + ); + paramTitle->setAlignment(Qt::AlignCenter); + paramMainLayout->addWidget(paramTitle); + QGridLayout *paramLayout = new QGridLayout(); - paramLayout->addWidget(new QLabel("移动速度:"), 0, 0); + paramLayout->setSpacing(12); + paramLayout->setContentsMargins(10, 10, 10, 10); + + // 移动速度 + QLabel *speedTitleLabel = new QLabel("移动速度:"); + speedTitleLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #ffffff; " // 白色字体确保可见性 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #3498db, stop:1 #2980b9);" // 蓝色渐变背景 + "border: 2px solid #2980b9; border-radius: 8px; " + "padding: 6px 12px; margin: 2px;" + ); + speedTitleLabel->setAlignment(Qt::AlignCenter); + paramLayout->addWidget(speedTitleLabel, 0, 0); + m_speedLabel = new QLabel("0.0 m/s"); - m_speedLabel->setStyleSheet("font-weight: bold; color: #16a085;"); + m_speedLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #2c3e50; " // 深色字体 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(22, 160, 133, 0.2), stop:1 rgba(26, 188, 156, 0.2));" // 增加背景透明度 + "border: 2px solid #16a085; border-radius: 8px; padding: 6px 12px; margin: 2px;" + ); + m_speedLabel->setAlignment(Qt::AlignCenter); paramLayout->addWidget(m_speedLabel, 0, 1); - paramLayout->addWidget(new QLabel("设备温度:"), 1, 0); + // 设备温度 + QLabel *tempTitleLabel = new QLabel("设备温度:"); + tempTitleLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #ffffff; " // 白色字体确保可见性 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #e67e22, stop:1 #d35400);" // 橙色渐变背景 + "border: 2px solid #d35400; border-radius: 8px; " + "padding: 6px 12px; margin: 2px;" + ); + tempTitleLabel->setAlignment(Qt::AlignCenter); + paramLayout->addWidget(tempTitleLabel, 1, 0); + m_temperatureLabel = new QLabel("35.2°C"); - m_temperatureLabel->setStyleSheet("font-weight: bold; color: #16a085;"); + m_temperatureLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #2c3e50; " // 深色字体 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(230, 126, 34, 0.2), stop:1 rgba(211, 84, 0, 0.2));" // 增加背景透明度 + "border: 2px solid #e67e22; border-radius: 8px; padding: 6px 12px; margin: 2px;" + ); + m_temperatureLabel->setAlignment(Qt::AlignCenter); paramLayout->addWidget(m_temperatureLabel, 1, 1); - paramLayout->addWidget(new QLabel("当前姿态:"), 2, 0); + // 当前姿态 + QLabel *postureTitleLabel = new QLabel("当前姿态:"); + postureTitleLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #ffffff; " // 白色字体确保可见性 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #8e44ad, stop:1 #7d3c98);" // 紫色渐变背景 + "border: 2px solid #7d3c98; border-radius: 8px; " + "padding: 6px 12px; margin: 2px;" + ); + postureTitleLabel->setAlignment(Qt::AlignCenter); + paramLayout->addWidget(postureTitleLabel, 2, 0); + m_postureLabel = new QLabel("🧍 站立"); + m_postureLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #2c3e50; " // 深色字体 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(142, 68, 173, 0.2), stop:1 rgba(155, 89, 182, 0.2));" // 增加背景透明度 + "border: 2px solid #8e44ad; border-radius: 8px; padding: 6px 12px; margin: 2px;" + ); + m_postureLabel->setAlignment(Qt::AlignCenter); paramLayout->addWidget(m_postureLabel, 2, 1); - paramLayout->addWidget(new QLabel("连接状态:"), 3, 0); + // 连接状态 + QLabel *connTitleLabel = new QLabel("连接状态:"); + connTitleLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #ffffff; " // 白色字体确保可见性 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #27ae60, stop:1 #229954);" // 绿色渐变背景 + "border: 2px solid #229954; border-radius: 8px; " + "padding: 6px 12px; margin: 2px;" + ); + connTitleLabel->setAlignment(Qt::AlignCenter); + paramLayout->addWidget(connTitleLabel, 3, 0); + m_connectionLabel = new QLabel("🟢 已连接"); + m_connectionLabel->setStyleSheet( + "font-size: 14px; font-weight: bold; color: #2c3e50; " // 深色字体 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 rgba(39, 174, 96, 0.2), stop:1 rgba(46, 204, 113, 0.2));" // 增加背景透明度 + "border: 2px solid #27ae60; border-radius: 8px; padding: 6px 12px; margin: 2px;" + ); + m_connectionLabel->setAlignment(Qt::AlignCenter); paramLayout->addWidget(m_connectionLabel, 3, 1); - statusLayout->addLayout(paramLayout); + // 设置列拉伸比例 + paramLayout->setColumnStretch(0, 1); + paramLayout->setColumnStretch(1, 1); + + paramMainLayout->addLayout(paramLayout); + statusLayout->addWidget(paramWidget); - // 日志显示 - QLabel *logLabel = new QLabel("系统日志:"); + // 日志显示 - 优化高度和样式 + QWidget *logWidget = new QWidget(); + logWidget->setObjectName("LogWidget"); + logWidget->setStyleSheet( + "QWidget#LogWidget {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #ffffff, stop:0.3 #f8f9fa, stop:1 #ecf0f1);" + " border: 3px solid #95a5a6;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + "}" + ); + + QVBoxLayout *logLayout = new QVBoxLayout(logWidget); + logLayout->setSpacing(10); + + QLabel *logLabel = new QLabel("📋 系统日志"); + logLabel->setStyleSheet( + "font-size: 16px; font-weight: bold; color: #ffffff; " // 白色字体确保可见性 + "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #95a5a6, stop:1 #7f8c8d);" // 灰色渐变背景 + "border: 2px solid #7f8c8d; border-radius: 10px; " // 保持圆角 + "padding: 8px 0px; margin-bottom: 8px;" // 增加内边距 + ); + logLabel->setAlignment(Qt::AlignCenter); + logLayout->addWidget(logLabel); + m_logTextEdit = new QTextEdit(); - m_logTextEdit->setMaximumHeight(200); + m_logTextEdit->setMaximumHeight(430); m_logTextEdit->setReadOnly(true); + m_logTextEdit->setStyleSheet( + "QTextEdit {" + " font-size: 12px;" + " color: #2c3e50;" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 #ffffff, stop:1 #f8f9fa);" + " border: 2px solid #95a5a6;" + " border-radius: 10px;" + " padding: 10px;" + " margin: 5px 0px;" + "}" + "QScrollBar:vertical {" + " background: #ecf0f1;" + " width: 12px;" + " border-radius: 6px;" + "}" + "QScrollBar::handle:vertical {" + " background: #95a5a6;" + " border-radius: 6px;" + " min-height: 20px;" + "}" + "QScrollBar::handle:vertical:hover {" + " background: #7f8c8d;" + "}" + ); m_logTextEdit->append(QString("[%1] 机器狗控制系统启动").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); m_logTextEdit->append(QString("[%1] 机器狗已连接,当前状态:待命").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - statusLayout->addWidget(logLabel); - statusLayout->addWidget(m_logTextEdit); + logLayout->addWidget(m_logTextEdit); + statusLayout->addWidget(logWidget); m_contentLayout->addWidget(m_statusGroup); } @@ -310,91 +972,270 @@ void RobotDogControlDialog::applyStyles() // 设置对话框样式 setStyleSheet( "QDialog {" - " background-color: #f8f9fa;" - " border: 1px solid #dee2e6;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #f8f9fa, stop:1 #e9ecef);" + " border: 2px solid #dee2e6;" + " border-radius: 15px;" "}" "QGroupBox {" " font-size: 16px;" " font-weight: bold;" " color: #495057;" " border: 2px solid #dee2e6;" - " border-radius: 8px;" - " margin-top: 10px;" - " padding-top: 10px;" + " border-radius: 12px;" + " margin-top: 15px;" + " padding-top: 15px;" + " background: rgba(255, 255, 255, 0.8);" "}" "QGroupBox::title {" " subcontrol-origin: margin;" - " left: 10px;" - " padding: 0 8px 0 8px;" - " background-color: #f8f9fa;" + " left: 15px;" + " padding: 5px 12px 5px 12px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #6c757d, stop:1 #495057);" + " color: white;" + " border-radius: 8px;" + " font-size: 14px;" "}" "QPushButton#DirectionBtn {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #16a085, stop:1 #138d75);" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #4fc3f7, stop:1 #29b6f6);" " color: white;" - " font-size: 14px;" + " font-size: 16px;" " font-weight: bold;" - " border: 2px solid #16a085;" - " border-radius: 8px;" - " padding: 8px;" + " border: 3px solid #29b6f6;" + " border-radius: 15px;" + " padding: 10px;" + " text-align: center;" "}" "QPushButton#DirectionBtn:hover {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #138d75, stop:1 #117a65);" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #81d4fa, stop:1 #4fc3f7);" + " border: 3px solid #4fc3f7;" + " transform: translateY(-3px);" + " box-shadow: 0 6px 12px rgba(79, 195, 247, 0.3);" "}" "QPushButton#DirectionBtn:pressed {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #117a65, stop:1 #0e6b5d);" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #29b6f6, stop:1 #0288d1);" + " border: 3px solid #0288d1;" + " transform: translateY(0px);" "}" "QPushButton#StopBtn {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #e67e22, stop:1 #d35400);" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ff7043, stop:1 #ff5722);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #ff5722;" + " border-radius: 15px;" + " padding: 10px;" + " text-align: center;" + "}" + "QPushButton#StopBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ff8a65, stop:1 #ff7043);" + " border: 3px solid #ff7043;" + " transform: translateY(-3px);" + " box-shadow: 0 6px 12px rgba(255, 112, 67, 0.3);" + "}" + "QPushButton#StopBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ff5722, stop:1 #e64a19);" + " border: 3px solid #e64a19;" + " transform: translateY(0px);" + "}" + "QPushButton#PostureBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #66bb6a, stop:1 #4caf50);" " color: white;" " font-size: 14px;" " font-weight: bold;" - " border: 2px solid #e67e22;" - " border-radius: 8px;" + " border: 3px solid #4caf50;" + " border-radius: 12px;" " padding: 8px;" + " text-align: center;" "}" - "QPushButton#PostureBtn {" - " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," - " stop:0 #3498db, stop:1 #2980b9);" + "QPushButton#PostureBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #81c784, stop:1 #66bb6a);" + " border: 3px solid #66bb6a;" + " transform: translateY(-2px);" + " box-shadow: 0 4px 8px rgba(102, 187, 106, 0.3);" + "}" + "QPushButton#PostureBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #4caf50, stop:1 #388e3c);" + " border: 3px solid #388e3c;" + " transform: translateY(0px);" + "}" + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" " color: white;" - " font-size: 13px;" + " font-size: 14px;" " font-weight: bold;" - " border: 2px solid #3498db;" - " border-radius: 6px;" - " padding: 6px;" + " border: 2px solid #9c27b0;" + " border-radius: 10px;" + " padding: 8px;" + " text-align: center;" "}" - "QSlider::groove:horizontal {" - " border: 1px solid #bbb;" - " background: white;" - " height: 10px;" - " border-radius: 4px;" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 2px solid #ab47bc;" + " transform: translateY(-2px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 2px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + "QPushButton#FunctionBtn:checked {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #e91e63, stop:1 #c2185b);" + " border: 2px solid #c2185b;" + "}" + "QPushButton#CloseBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #78909c, stop:1 #607d8b);" + " color: white;" + " font-size: 14px;" + " font-weight: bold;" + " border: 2px solid #607d8b;" + " border-radius: 8px;" + " padding: 8px 16px;" + "}" + "QPushButton#CloseBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #90a4ae, stop:1 #78909c);" + " border: 2px solid #78909c;" + "}" + "QPushButton#ModernDirectionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #4fc3f7, stop:0.5 #29b6f6, stop:1 #0288d1);" + " color: black;" + " font-size: 12px;" + " font-weight: bold;" + " border: 2px solid #0288d1;" + " border-radius: 10px;" + " padding: 4px;" + " text-align: center;" + " line-height: 1.2;" "}" - "QSlider::handle:horizontal {" - " background: #16a085;" - " border: 1px solid #5c5c5c;" - " width: 18px;" - " margin: -2px 0;" - " border-radius: 3px;" + "QPushButton#ModernDirectionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #81d4fa, stop:0.5 #4fc3f7, stop:1 #29b6f6);" + " border: 2px solid #29b6f6;" + " color: black;" + " transform: translateY(-2px);" + " box-shadow: 0 4px 8px rgba(79, 195, 247, 0.4);" + "}" + "QPushButton#ModernDirectionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #29b6f6, stop:0.5 #0288d1, stop:1 #0277bd);" + " border: 2px solid #0277bd;" + " color: black;" + " transform: translateY(0px);" + "}" + "QPushButton#ModernStopBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ff7043, stop:0.5 #ff5722, stop:1 #e64a19);" + " color: black;" + " font-size: 12px;" + " font-weight: bold;" + " border: 2px solid #e64a19;" + " border-radius: 10px;" + " padding: 4px;" + " text-align: center;" + " line-height: 1.2;" + "}" + "QPushButton#ModernStopBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ff8a65, stop:0.5 #ff7043, stop:1 #ff5722);" + " border: 2px solid #ff5722;" + " color: black;" + " transform: translateY(-2px);" + " box-shadow: 0 4px 8px rgba(255, 112, 67, 0.4);" + "}" + "QPushButton#ModernStopBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ff5722, stop:0.5 #e64a19, stop:1 #d84315);" + " border: 2px solid #d84315;" + " color: black;" + " transform: translateY(0px);" + "}" + "QPushButton#ModernPostureBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #66bb6a, stop:0.5 #4caf50, stop:1 #388e3c);" + " color: white;" + " font-size: 14px;" + " font-weight: bold;" + " border: 2px solid #388e3c;" + " border-radius: 12px;" + " padding: 8px;" + " text-align: center;" + "}" + "QPushButton#ModernPostureBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #81c784, stop:0.5 #66bb6a, stop:1 #4caf50);" + " border: 2px solid #4caf50;" + " transform: translateY(-2px);" + " box-shadow: 0 4px 8px rgba(102, 187, 106, 0.4);" + "}" + "QPushButton#ModernPostureBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #4caf50, stop:0.5 #388e3c, stop:1 #2e7d32);" + " border: 2px solid #2e7d32;" + " transform: translateY(0px);" "}" "QProgressBar {" " border: 2px solid #dee2e6;" - " border-radius: 5px;" + " border-radius: 8px;" " text-align: center;" " font-weight: bold;" + " background: #f8f9fa;" + " color: #495057;" "}" "QProgressBar::chunk {" - " background-color: #28a745;" - " border-radius: 3px;" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0, " + " stop:0 #28a745, stop:1 #20c997);" + " border-radius: 6px;" "}" "QTextEdit {" - " border: 1px solid #dee2e6;" - " border-radius: 4px;" - " background-color: white;" - " font-family: 'Consolas', monospace;" + " border: 2px solid #dee2e6;" + " border-radius: 8px;" + " background: qlineargradient(x1:0, y1:0, x2:0, y2:1, " + " stop:0 #ffffff, stop:1 #f8f9fa);" + " font-family: 'Consolas', 'Monaco', monospace;" " font-size: 12px;" + " color: #495057;" + " padding: 8px;" + "}" + "QComboBox {" + " border: 2px solid #dee2e6;" + " border-radius: 8px;" + " padding: 5px 10px;" + " background: white;" + " color: #495057;" + " font-size: 13px;" + "}" + "QComboBox:hover {" + " border: 2px solid #6c757d;" + "}" + "QComboBox::drop-down {" + " border: none;" + " width: 20px;" + "}" + "QComboBox::down-arrow {" + " image: url(:/icons/arrow_down.png);" + " width: 12px;" + " height: 12px;" + "}" + "QLabel {" + " color: #495057;" + " font-size: 13px;" "}" ); } @@ -416,11 +1257,10 @@ void RobotDogControlDialog::connectSignals() // 紧急停止 connect(m_emergencyStopBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onEmergencyStop); - // 任务控制信号连接 - connect(m_mappingBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onMappingToggle); - connect(m_navigationBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onNavigationToggle); - connect(m_photoBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onPhotoTransmissionToggle); - connect(m_recognitionBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onPersonRecognitionToggle); + // 任务控制信号连接(雷达控制) + connect(m_slamRadarBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onSlamRadarToggle); + connect(m_radarMappingBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onRadarMappingToggle); + connect(m_autoNavMappingBtn, &QPushButton::clicked, this, &RobotDogControlDialog::onAutoNavMappingToggle); // 速度滑块 connect(m_speedSlider, &QSlider::valueChanged, [this](int value) { @@ -546,85 +1386,981 @@ void RobotDogControlDialog::onEmergencyStop() onStopClicked(); // 停止所有任务 - if (m_isMappingActive) onMappingToggle(); - if (m_isNavigationActive) onNavigationToggle(); - if (m_isPhotoTransmissionActive) onPhotoTransmissionToggle(); - if (m_isPersonRecognitionActive) onPersonRecognitionToggle(); + if (m_isSlamRadarActive) onSlamRadarToggle(); + if (m_isRadarMappingActive) onRadarMappingToggle(); + if (m_isAutoNavMappingActive) onAutoNavMappingToggle(); } } // 任务控制槽函数实现 -void RobotDogControlDialog::onMappingToggle() +void RobotDogControlDialog::onSlamRadarToggle() +{ + m_isSlamRadarActive = !m_isSlamRadarActive; + + if (m_isSlamRadarActive) { + m_slamRadarBtn->setText("🌐 停止思岚雷达"); + m_slamRadarBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #27ae60, stop:1 #2ecc71);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #27ae60;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #2ecc71, stop:1 #58d68d);" + " border: 3px solid #2ecc71;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #229954, stop:1 #1e8449);" + " border: 3px solid #1e8449;" + " transform: translateY(0px);" + "}" + ); + m_logTextEdit->append(QString("[%1] 启动思岚雷达").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 更新雷达显示为连接状态 + m_radarDisplayLabel->setText("思岚雷达连接中...\n\n🌐\n\n正在建立SSH连接"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #27ae60, stop:0.5 #2ecc71, stop:1 #27ae60);" + " border: 3px solid #27ae60;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + + // 执行SSH命令启动思岚雷达 + executeSlamRadarCommands(); + + emit startSlamRadar(); + } else { + m_slamRadarBtn->setText("🌐 启动思岚雷达"); + m_slamRadarBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + m_logTextEdit->append(QString("[%1] 停止思岚雷达").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + + // 停止SSH进程 + stopSlamRadarProcess(); + + emit stopSlamRadar(); + } +} + +void RobotDogControlDialog::onRadarMappingToggle() +{ + m_isRadarMappingActive = !m_isRadarMappingActive; + + if (m_isRadarMappingActive) { + m_radarMappingBtn->setText("🗺️ 停止雷达建图"); + m_radarMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #27ae60, stop:1 #2ecc71);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #27ae60;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #2ecc71, stop:1 #58d68d);" + " border: 3px solid #2ecc71;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #229954, stop:1 #1e8449);" + " border: 3px solid #1e8449;" + " transform: translateY(0px);" + "}" + ); + m_logTextEdit->append(QString("[%1] 启动雷达建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 更新雷达显示为建图模式 + m_radarDisplayLabel->setText("雷达建图中...\n\n🗺️\n\n正在构建环境地图"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #3498db, stop:0.5 #2980b9, stop:1 #3498db);" + " border: 3px solid #2980b9;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + + // 执行本地雷达建图命令 + executeRadarMappingCommands(); + + emit startRadarMapping(); + } else { + m_radarMappingBtn->setText("🗺️ 启动雷达建图"); + m_radarMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + m_logTextEdit->append(QString("[%1] 停止雷达建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + + // 停止雷达建图进程 + stopRadarMappingProcess(); + + emit stopRadarMapping(); + } +} + +void RobotDogControlDialog::onAutoNavMappingToggle() +{ + m_isAutoNavMappingActive = !m_isAutoNavMappingActive; + + if (m_isAutoNavMappingActive) { + m_autoNavMappingBtn->setText("🧭 停止自动导航建图"); + m_autoNavMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #27ae60, stop:1 #2ecc71);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #27ae60;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #2ecc71, stop:1 #58d68d);" + " border: 3px solid #2ecc71;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #229954, stop:1 #1e8449);" + " border: 3px solid #1e8449;" + " transform: translateY(0px);" + "}" + ); + m_logTextEdit->append(QString("[%1] 启动自动导航建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 更新雷达显示为导航建图模式 + m_radarDisplayLabel->setText("自动导航建图中...\n\n🧭\n\n智能路径规划进行中"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #9b59b6, stop:0.5 #8e44ad, stop:1 #9b59b6);" + " border: 3px solid #8e44ad;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + + // 执行本地自动导航建图命令 + executeAutoNavMappingCommands(); + + emit startAutoNavMapping(); + } else { + m_autoNavMappingBtn->setText("🧭 启动自动导航建图"); + m_autoNavMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + m_logTextEdit->append(QString("[%1] 停止自动导航建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + + // 停止自动导航建图进程 + stopAutoNavMappingProcess(); + + emit stopAutoNavMapping(); + } +} + +void RobotDogControlDialog::updateRobotStatus(int battery, double speed, double temperature) { - m_isMappingActive = !m_isMappingActive; + m_batteryProgress->setValue(battery); + m_speedLabel->setText(QString("%1 m/s").arg(speed, 0, 'f', 1)); + m_temperatureLabel->setText(QString("%1°C").arg(temperature, 0, 'f', 1)); +} - if (m_isMappingActive) { - m_mappingBtn->setText("🗺️ 停止建图"); - m_mappingBtn->setStyleSheet("background-color: #dc3545; color: white;"); - m_logTextEdit->append(QString("[%1] 开始自主建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit startMapping(); +void RobotDogControlDialog::executeSlamRadarCommands() +{ + if (m_sshProcess->state() != QProcess::NotRunning) { + m_logTextEdit->append(QString("[%1] SSH进程正在运行中...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + return; + } + + m_logTextEdit->append(QString("[%1] 开始在新终端中连接思岚雷达设备...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 连接地址: %2@%3").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(m_radarUser).arg(m_radarHost)); + + // 创建简化的SSH命令,添加ROS环境设置和简单调试信息 + QString sshCommands = QString( + "sshpass -p '%3' ssh -o StrictHostKeyChecking=no %1@%2 '" + "echo \"连接成功,当前目录: $(pwd)\" && " + "source /opt/ros/melodic/setup.bash && " + "echo \"ROS环境已设置\" && " + "cd catkin_ws && " + "echo \"进入catkin_ws目录: $(pwd)\" && " + "catkin_make && " + "echo \"编译完成\" && " + "source devel/setup.bash && " + "echo \"工作空间环境已设置\" && " + "roslaunch slamware_ros_sdk go1_slamware_bridge.launch" + "'" + ).arg(m_radarUser).arg(m_radarHost).arg(m_radarPassword); + + // 在新的终端窗口中启动SSH连接和命令执行 + QStringList terminalCommands; + + // 尝试使用gnome-terminal + QString terminalCommand = "gnome-terminal"; + QStringList terminalArgs; + terminalArgs << "--title=思岚雷达SSH连接-GO1" + << "--geometry=100x30" + << "--" + << "bash" + << "-c" + << sshCommands + " ; echo '' ; echo '=== 执行完成 ===' ; echo '按任意键关闭终端或Ctrl+C强制退出...' ; read -n 1"; + + m_logTextEdit->append(QString("[%1] 在新终端窗口中启动SSH连接...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 终端标题: 思岚雷达SSH连接-GO1").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 启动新终端进程 + m_sshProcess->start(terminalCommand, terminalArgs); + + if (!m_sshProcess->waitForStarted(3000)) { + // 如果gnome-terminal失败,尝试使用xterm + m_logTextEdit->append(QString("[%1] gnome-terminal不可用,尝试使用xterm...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + terminalCommand = "xterm"; + terminalArgs.clear(); + terminalArgs << "-title" << "思岚雷达SSH连接-GO1" + << "-geometry" << "100x30" + << "-hold" + << "-e" + << "bash" + << "-c" + << sshCommands; + + m_sshProcess->start(terminalCommand, terminalArgs); + + if (!m_sshProcess->waitForStarted(3000)) { + // 最后尝试使用konsole(KDE终端) + m_logTextEdit->append(QString("[%1] xterm不可用,尝试使用konsole...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + terminalCommand = "konsole"; + terminalArgs.clear(); + terminalArgs << "--title" << "思岚雷达SSH连接-GO1" + << "-e" + << "bash" + << "-c" + << sshCommands + " ; echo '按任意键关闭终端...' ; read -n 1"; + + m_sshProcess->start(terminalCommand, terminalArgs); + + if (!m_sshProcess->waitForStarted(3000)) { + m_logTextEdit->append(QString("[%1] ❌ 无法启动终端,请确保系统安装了gnome-terminal、xterm或konsole").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 💡 您也可以手动在终端中执行以下命令:").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] sshpass -p '123' ssh unitree@192.168.123.15").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + return; + } + } + } + + m_logTextEdit->append(QString("[%1] ✅ 新终端窗口已打开").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 🔄 正在新终端中执行SSH连接和思岚雷达启动...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 📋 执行步骤:").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 1. SSH连接到 unitree@192.168.123.15").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 2. 智能检测并设置ROS环境变量").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 3. 切换到/创建 catkin_ws 目录").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 4. 智能检测catkin_make并尝试编译(可选)").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 5. 设置工作空间环境变量").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 6. 启动思岚雷达节点(多包兼容)").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] ⚠️ 已优化错误处理,即使catkin_make不可用也会尝试启动雷达").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); +} + +void RobotDogControlDialog::stopSlamRadarProcess() +{ + if (m_sshProcess->state() != QProcess::NotRunning) { + m_logTextEdit->append(QString("[%1] 正在停止思岚雷达终端进程...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 发送终止信号到终端进程 + m_sshProcess->terminate(); + + // 等待进程结束,如果超时则强制杀死 + if (!m_sshProcess->waitForFinished(3000)) { + m_logTextEdit->append(QString("[%1] 强制终止终端进程").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_sshProcess->kill(); + } + + m_logTextEdit->append(QString("[%1] ✅ 思岚雷达终端进程已停止").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_logTextEdit->append(QString("[%1] 💡 注意: 如果SSH连接仍在终端中运行,请手动在终端中按Ctrl+C停止").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); } else { - m_mappingBtn->setText("🗺️ 开始建图"); - m_mappingBtn->setStyleSheet(""); - m_logTextEdit->append(QString("[%1] 停止自主建图").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit stopMapping(); + m_logTextEdit->append(QString("[%1] 终端进程未运行").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); } } -void RobotDogControlDialog::onNavigationToggle() +void RobotDogControlDialog::onSshProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { - m_isNavigationActive = !m_isNavigationActive; + if (exitStatus == QProcess::CrashExit) { + m_logTextEdit->append(QString("[%1] ❌ SSH进程异常退出,退出码: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(exitCode)); + + // 如果雷达处于活动状态,自动切换状态 + if (m_isSlamRadarActive) { + m_isSlamRadarActive = false; + m_slamRadarBtn->setText("🌐 启动思岚雷达"); + m_slamRadarBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 18px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" // 从80减少到50 + " max-height: 50px;" // 从80减少到50 + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + } + } else { + m_logTextEdit->append(QString("[%1] ✅ SSH进程正常结束,退出码: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(exitCode)); + } +} + +void RobotDogControlDialog::onSshProcessError(QProcess::ProcessError error) +{ + QString errorString; + switch (error) { + case QProcess::FailedToStart: + errorString = "SSH进程启动失败"; + break; + case QProcess::Crashed: + errorString = "SSH进程崩溃"; + break; + case QProcess::Timedout: + errorString = "SSH连接超时"; + break; + case QProcess::WriteError: + errorString = "SSH写入错误"; + break; + case QProcess::ReadError: + errorString = "SSH读取错误"; + break; + default: + errorString = "SSH未知错误"; + } + + m_logTextEdit->append(QString("[%1] ❌ SSH连接错误: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss"), errorString)); + + // 重置雷达状态 + if (m_isSlamRadarActive) { + m_isSlamRadarActive = false; + m_slamRadarBtn->setText("🌐 启动思岚雷达"); + m_slamRadarBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 18px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" // 从80减少到50 + " max-height: 50px;" // 从80减少到50 + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达连接失败\n\n❌\n\n请检查网络连接"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #e74c3c, stop:0.5 #c0392b, stop:1 #e74c3c);" + " border: 3px solid #c0392b;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + } +} - if (m_isNavigationActive) { - m_navigationBtn->setText("🧭 停止导航"); - m_navigationBtn->setStyleSheet("background-color: #dc3545; color: white;"); - m_logTextEdit->append(QString("[%1] 开始导航避障").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit startNavigation(); +void RobotDogControlDialog::executeRadarMappingCommands() +{ + if (m_radarMappingProcess->state() != QProcess::NotRunning) { + m_logTextEdit->append(QString("[%1] 雷达建图进程已在运行中").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + return; + } + + m_logTextEdit->append(QString("[%1] 开始执行雷达建图命令...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 创建完整的命令脚本 + QString commandScript = + "cd .. && " + "cd catkin_dog && " + "catkin_make && " + "source devel/setup.bash && " + "roslaunch unitree_legged_real pc_slamware_receiver.launch"; + + // 使用bash执行命令序列 + QStringList arguments; + arguments << "-c" << commandScript; + + m_logTextEdit->append(QString("[%1] 执行命令: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss"), commandScript)); + + // 启动进程 + m_radarMappingProcess->start("bash", arguments); + + if (!m_radarMappingProcess->waitForStarted(5000)) { + m_logTextEdit->append(QString("[%1] 雷达建图进程启动失败").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); } else { - m_navigationBtn->setText("🧭 导航避障"); - m_navigationBtn->setStyleSheet(""); - m_logTextEdit->append(QString("[%1] 停止导航避障").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit stopNavigation(); + m_logTextEdit->append(QString("[%1] 雷达建图进程启动成功").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); } } -void RobotDogControlDialog::onPhotoTransmissionToggle() +void RobotDogControlDialog::stopRadarMappingProcess() { - m_isPhotoTransmissionActive = !m_isPhotoTransmissionActive; + if (m_radarMappingProcess->state() == QProcess::NotRunning) { + m_logTextEdit->append(QString("[%1] 雷达建图进程未运行").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + return; + } - if (m_isPhotoTransmissionActive) { - m_photoBtn->setText("📸 停止传输"); - m_photoBtn->setStyleSheet("background-color: #dc3545; color: white;"); - m_logTextEdit->append(QString("[%1] 开始照片传输").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit startPhotoTransmission(); + m_logTextEdit->append(QString("[%1] 正在停止雷达建图进程...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 优雅地终止进程 + m_radarMappingProcess->terminate(); + + // 等待进程结束,如果超时则强制杀死 + if (!m_radarMappingProcess->waitForFinished(5000)) { + m_logTextEdit->append(QString("[%1] 进程未响应,强制终止").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_radarMappingProcess->kill(); + m_radarMappingProcess->waitForFinished(2000); + } + + m_logTextEdit->append(QString("[%1] 雷达建图进程已停止").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); +} + +void RobotDogControlDialog::onRadarMappingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus == QProcess::CrashExit) { + m_logTextEdit->append(QString("[%1] 雷达建图进程崩溃,退出码: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(exitCode)); } else { - m_photoBtn->setText("📸 照片传输"); - m_photoBtn->setStyleSheet(""); - m_logTextEdit->append(QString("[%1] 停止照片传输").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit stopPhotoTransmission(); + m_logTextEdit->append(QString("[%1] 雷达建图进程正常结束,退出码: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(exitCode)); + } + + // 如果进程意外结束,重置UI状态 + if (m_isRadarMappingActive) { + m_isRadarMappingActive = false; + m_radarMappingBtn->setText("🗺️ 启动雷达建图"); + m_radarMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + } +} + +void RobotDogControlDialog::onRadarMappingProcessError(QProcess::ProcessError error) +{ + QString errorString; + switch (error) { + case QProcess::FailedToStart: + errorString = "雷达建图进程启动失败"; + break; + case QProcess::Crashed: + errorString = "雷达建图进程崩溃"; + break; + case QProcess::Timedout: + errorString = "雷达建图进程超时"; + break; + case QProcess::WriteError: + errorString = "雷达建图写入错误"; + break; + case QProcess::ReadError: + errorString = "雷达建图读取错误"; + break; + default: + errorString = "雷达建图未知错误"; + } + + m_logTextEdit->append(QString("[%1] 雷达建图进程错误: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss"), errorString)); + + // 重置UI状态 + if (m_isRadarMappingActive) { + m_isRadarMappingActive = false; + m_radarMappingBtn->setText("🗺️ 启动雷达建图"); + m_radarMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达建图失败\n\n❌\n\n请检查ROS环境"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #e74c3c, stop:0.5 #c0392b, stop:1 #e74c3c);" + " border: 3px solid #c0392b;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); } } -void RobotDogControlDialog::onPersonRecognitionToggle() +void RobotDogControlDialog::executeAutoNavMappingCommands() { - m_isPersonRecognitionActive = !m_isPersonRecognitionActive; + if (m_autoNavMappingProcess->state() != QProcess::NotRunning) { + m_logTextEdit->append(QString("[%1] 自动导航建图进程已在运行中").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + return; + } - if (m_isPersonRecognitionActive) { - m_recognitionBtn->setText("👁️ 停止识别"); - m_recognitionBtn->setStyleSheet("background-color: #dc3545; color: white;"); - m_logTextEdit->append(QString("[%1] 开始人物识别").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit startPersonRecognition(); + m_logTextEdit->append(QString("[%1] 开始执行自动导航建图命令...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 创建完整的命令脚本 + QString commandScript = + "cd .. && " + "cd catkin_dog && " + "catkin_make && " + "source devel/setup.bash && " + "roslaunch unitree_legged_real go1_navigation.launch"; + + // 使用bash执行命令序列 + QStringList arguments; + arguments << "-c" << commandScript; + + m_logTextEdit->append(QString("[%1] 执行命令: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss"), commandScript)); + + // 启动进程 + m_autoNavMappingProcess->start("bash", arguments); + + if (!m_autoNavMappingProcess->waitForStarted(5000)) { + m_logTextEdit->append(QString("[%1] 自动导航建图进程启动失败").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); } else { - m_recognitionBtn->setText("👁️ 人物识别"); - m_recognitionBtn->setStyleSheet(""); - m_logTextEdit->append(QString("[%1] 停止人物识别").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); - emit stopPersonRecognition(); + m_logTextEdit->append(QString("[%1] 自动导航建图进程启动成功").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); } } -void RobotDogControlDialog::updateRobotStatus(int battery, double speed, double temperature) +void RobotDogControlDialog::stopAutoNavMappingProcess() { - m_batteryProgress->setValue(battery); - m_speedLabel->setText(QString("%1 m/s").arg(speed, 0, 'f', 1)); - m_temperatureLabel->setText(QString("%1°C").arg(temperature, 0, 'f', 1)); + if (m_autoNavMappingProcess->state() == QProcess::NotRunning) { + m_logTextEdit->append(QString("[%1] 自动导航建图进程未运行").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + return; + } + + m_logTextEdit->append(QString("[%1] 正在停止自动导航建图进程...").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + + // 优雅地终止进程 + m_autoNavMappingProcess->terminate(); + + // 等待进程结束,如果超时则强制杀死 + if (!m_autoNavMappingProcess->waitForFinished(5000)) { + m_logTextEdit->append(QString("[%1] 进程未响应,强制终止").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); + m_autoNavMappingProcess->kill(); + m_autoNavMappingProcess->waitForFinished(2000); + } + + m_logTextEdit->append(QString("[%1] 自动导航建图进程已停止").arg(QDateTime::currentDateTime().toString("hh:mm:ss"))); +} + +void RobotDogControlDialog::onAutoNavMappingProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + if (exitStatus == QProcess::CrashExit) { + m_logTextEdit->append(QString("[%1] 自动导航建图进程崩溃,退出码: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(exitCode)); + } else { + m_logTextEdit->append(QString("[%1] 自动导航建图进程正常结束,退出码: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss")).arg(exitCode)); + } + + // 如果进程意外结束,重置UI状态 + if (m_isAutoNavMappingActive) { + m_isAutoNavMappingActive = false; + m_autoNavMappingBtn->setText("🧭 启动自动导航建图"); + m_autoNavMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("雷达待机中...\n\n🔄\n\n启动雷达后显示扫描图像"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #1e3c72, stop:0.5 #2a5298, stop:1 #1e3c72);" + " border: 3px solid #34495e;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: #bdc3c7;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + } +} + +void RobotDogControlDialog::onAutoNavMappingProcessError(QProcess::ProcessError error) +{ + QString errorString; + switch (error) { + case QProcess::FailedToStart: + errorString = "自动导航建图进程启动失败"; + break; + case QProcess::Crashed: + errorString = "自动导航建图进程崩溃"; + break; + case QProcess::Timedout: + errorString = "自动导航建图进程超时"; + break; + case QProcess::WriteError: + errorString = "自动导航建图写入错误"; + break; + case QProcess::ReadError: + errorString = "自动导航建图读取错误"; + break; + default: + errorString = "自动导航建图未知错误"; + } + + m_logTextEdit->append(QString("[%1] 自动导航建图进程错误: %2").arg(QDateTime::currentDateTime().toString("hh:mm:ss"), errorString)); + + // 重置UI状态 + if (m_isAutoNavMappingActive) { + m_isAutoNavMappingActive = false; + m_autoNavMappingBtn->setText("🧭 启动自动导航建图"); + m_autoNavMappingBtn->setStyleSheet( + "QPushButton#FunctionBtn {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ab47bc, stop:1 #9c27b0);" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + " border: 3px solid #9c27b0;" + " border-radius: 15px;" + " padding: 15px;" + " text-align: center;" + " margin: 5px 0px;" + " min-height: 50px;" + " max-height: 50px;" + "}" + "QPushButton#FunctionBtn:hover {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #ba68c8, stop:1 #ab47bc);" + " border: 3px solid #ab47bc;" + " transform: translateY(-3px);" + "}" + "QPushButton#FunctionBtn:pressed {" + " background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1," + " stop:0 #9c27b0, stop:1 #7b1fa2);" + " border: 3px solid #7b1fa2;" + " transform: translateY(0px);" + "}" + ); + + // 恢复雷达显示待机状态 + m_radarDisplayLabel->setText("自动导航建图失败\n\n❌\n\n请检查ROS环境"); + m_radarDisplayLabel->setStyleSheet( + "QLabel#RadarDisplay {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:1, " + " stop:0 #e74c3c, stop:0.5 #c0392b, stop:1 #e74c3c);" + " border: 3px solid #c0392b;" + " border-radius: 15px;" + " padding: 15px;" + " margin: 5px;" + " color: white;" + " font-size: 16px;" + " font-weight: bold;" + "}" + ); + } } diff --git a/src/catkin_dog/src/unitree_ros_to_real/unitree_legged_real/rviz/slamware_display.rviz b/src/catkin_dog/src/unitree_ros_to_real/unitree_legged_real/rviz/slamware_display.rviz index e940fcac..c66ae876 100644 --- a/src/catkin_dog/src/unitree_ros_to_real/unitree_legged_real/rviz/slamware_display.rviz +++ b/src/catkin_dog/src/unitree_ros_to_real/unitree_legged_real/rviz/slamware_display.rviz @@ -136,7 +136,7 @@ Visualization Manager: Shaft Length: 0.8 Shaft Radius: 0.05000000074505806 Value: Arrow - Topic: /robot_odom + Topic: /robot_pose Unreliable: false Value: true @@ -144,7 +144,7 @@ Visualization Manager: - Alpha: 1 Axes Length: 0.8 Axes Radius: 0.08 - Class: rviz/PoseWithCovariance + Class: rviz/Pose Color: 255; 25; 0 Enabled: true Head Length: 0.30000001192092896 @@ -154,7 +154,7 @@ Visualization Manager: Shaft Length: 1.2 Shaft Radius: 0.08 Shape: Arrow - Topic: /robot_pose + Topic: /robot_pose_arrow Unreliable: false Value: true