GrabBag/Tools/RobotView/MainWindow.cpp

921 lines
32 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file MainWindow.cpp
* @brief 机器人控制测试工具主窗口实现
*/
#include "MainWindow.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QTextEdit>
#include <QTabWidget>
#include <QDateTime>
#include <QMessageBox>
#include <QSplitter>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, robot_(std::make_unique<FairinoRobotWrapper>())
, refreshTimer_(new QTimer(this))
{
setupUI();
setupConnections();
// 显示SDK版本
lblSDKVersion_->setText(QString("SDK版本: %1").arg(QString::fromStdString(robot_->GetSDKVersion())));
updateConnectionState(false);
}
MainWindow::~MainWindow()
{
if (robot_->IsConnected()) {
robot_->Disconnect();
}
}
void MainWindow::setupUI()
{
setWindowTitle("RobotView - 机器人测试工具");
setMinimumSize(900, 580);
QWidget* centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
QVBoxLayout* mainLayout = new QVBoxLayout(centralWidget);
mainLayout->setSpacing(5);
mainLayout->setContentsMargins(5, 5, 5, 5);
// ========== 顶部连接控制区 ==========
QGroupBox* groupConnection = new QGroupBox("连接控制", this);
QHBoxLayout* connLayout = new QHBoxLayout(groupConnection);
connLayout->addWidget(new QLabel("IP地址:"));
editIP_ = new QLineEdit("192.168.58.2");
editIP_->setFixedWidth(150);
connLayout->addWidget(editIP_);
btnConnect_ = new QPushButton("连接");
btnDisconnect_ = new QPushButton("断开");
btnEnable_ = new QPushButton("上使能");
btnDisable_ = new QPushButton("下使能");
btnResetError_ = new QPushButton("清除错误");
connLayout->addWidget(btnConnect_);
connLayout->addWidget(btnDisconnect_);
connLayout->addWidget(btnEnable_);
connLayout->addWidget(btnDisable_);
connLayout->addWidget(btnResetError_);
lblConnectionStatus_ = new QLabel("未连接");
lblConnectionStatus_->setStyleSheet("color: red; font-weight: bold;");
connLayout->addWidget(lblConnectionStatus_);
connLayout->addStretch();
lblSDKVersion_ = new QLabel("SDK版本: ");
connLayout->addWidget(lblSDKVersion_);
mainLayout->addWidget(groupConnection);
// ========== 中间区域左侧Tab + 右侧状态 ==========
QHBoxLayout* middleLayout = new QHBoxLayout();
middleLayout->setSpacing(5);
// --- 左侧 Tab 控件 ---
tabWidget_ = new QTabWidget(this);
// === Tab 1: 运动控制 ===
QWidget* tabMotion = new QWidget();
QVBoxLayout* motionLayout = new QVBoxLayout(tabMotion);
// 运动参数区
QGroupBox* groupParams = new QGroupBox("运动参数", tabMotion);
QHBoxLayout* paramsLayout = new QHBoxLayout(groupParams);
paramsLayout->addWidget(new QLabel("速度(%):"));
spinVel_ = new QSpinBox();
spinVel_->setRange(1, 100);
spinVel_->setValue(30);
paramsLayout->addWidget(spinVel_);
paramsLayout->addWidget(new QLabel("加速度(%):"));
spinAcc_ = new QSpinBox();
spinAcc_->setRange(1, 100);
spinAcc_->setValue(30);
paramsLayout->addWidget(spinAcc_);
paramsLayout->addWidget(new QLabel("工具号:"));
spinTool_ = new QSpinBox();
spinTool_->setRange(0, 14);
paramsLayout->addWidget(spinTool_);
paramsLayout->addWidget(new QLabel("工件号:"));
spinUser_ = new QSpinBox();
spinUser_->setRange(0, 14);
paramsLayout->addWidget(spinUser_);
paramsLayout->addStretch();
motionLayout->addWidget(groupParams);
// 位姿输入区MoveL 和 MoveJ 共用)
QGroupBox* groupPose = new QGroupBox("位姿运动 MoveL / MoveJ (mm/deg)", tabMotion);
QGridLayout* poseLayout = new QGridLayout(groupPose);
poseLayout->setHorizontalSpacing(5); // 减小水平间距
QLabel* lblX = new QLabel("X:");
lblX->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
poseLayout->addWidget(lblX, 0, 0);
spinPoseX_ = new QDoubleSpinBox();
spinPoseX_->setRange(-2000, 2000);
spinPoseX_->setDecimals(2);
spinPoseX_->setValue(400);
poseLayout->addWidget(spinPoseX_, 0, 1);
QLabel* lblY = new QLabel("Y:");
lblY->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
poseLayout->addWidget(lblY, 0, 2);
spinPoseY_ = new QDoubleSpinBox();
spinPoseY_->setRange(-2000, 2000);
spinPoseY_->setDecimals(2);
spinPoseY_->setValue(0);
poseLayout->addWidget(spinPoseY_, 0, 3);
QLabel* lblZ = new QLabel("Z:");
lblZ->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
poseLayout->addWidget(lblZ, 0, 4);
spinPoseZ_ = new QDoubleSpinBox();
spinPoseZ_->setRange(-2000, 2000);
spinPoseZ_->setDecimals(2);
spinPoseZ_->setValue(300);
poseLayout->addWidget(spinPoseZ_, 0, 5);
QLabel* lblRx = new QLabel("Rx:");
lblRx->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
poseLayout->addWidget(lblRx, 1, 0);
spinPoseRx_ = new QDoubleSpinBox();
spinPoseRx_->setRange(-180, 180);
spinPoseRx_->setDecimals(2);
spinPoseRx_->setValue(180);
poseLayout->addWidget(spinPoseRx_, 1, 1);
QLabel* lblRy = new QLabel("Ry:");
lblRy->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
poseLayout->addWidget(lblRy, 1, 2);
spinPoseRy_ = new QDoubleSpinBox();
spinPoseRy_->setRange(-180, 180);
spinPoseRy_->setDecimals(2);
spinPoseRy_->setValue(0);
poseLayout->addWidget(spinPoseRy_, 1, 3);
QLabel* lblRz = new QLabel("Rz:");
lblRz->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
poseLayout->addWidget(lblRz, 1, 4);
spinPoseRz_ = new QDoubleSpinBox();
spinPoseRz_->setRange(-180, 180);
spinPoseRz_->setDecimals(2);
spinPoseRz_->setValue(0);
poseLayout->addWidget(spinPoseRz_, 1, 5);
// 按钮行
QHBoxLayout* poseBtnLayout = new QHBoxLayout();
btnMoveL_ = new QPushButton("MoveL 直线");
btnMoveJPose_ = new QPushButton("MoveJ 关节");
btnSyncPose_ = new QPushButton("同步当前位姿");
poseBtnLayout->addWidget(btnMoveL_);
poseBtnLayout->addWidget(btnMoveJPose_);
poseBtnLayout->addWidget(btnSyncPose_);
poseBtnLayout->addStretch();
poseLayout->addLayout(poseBtnLayout, 2, 0, 1, 6);
motionLayout->addWidget(groupPose);
// 关节角度输入区
QGroupBox* groupJoint = new QGroupBox("关节运动 MoveJ (deg)", tabMotion);
QGridLayout* jointLayout = new QGridLayout(groupJoint);
jointLayout->setHorizontalSpacing(5);
QLabel* lblJ1 = new QLabel("J1:");
lblJ1->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
jointLayout->addWidget(lblJ1, 0, 0);
spinJoint1_ = new QDoubleSpinBox();
spinJoint1_->setRange(-180, 180);
spinJoint1_->setDecimals(2);
jointLayout->addWidget(spinJoint1_, 0, 1);
QLabel* lblJ2 = new QLabel("J2:");
lblJ2->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
jointLayout->addWidget(lblJ2, 0, 2);
spinJoint2_ = new QDoubleSpinBox();
spinJoint2_->setRange(-180, 180);
spinJoint2_->setDecimals(2);
spinJoint2_->setValue(-45);
jointLayout->addWidget(spinJoint2_, 0, 3);
QLabel* lblJ3 = new QLabel("J3:");
lblJ3->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
jointLayout->addWidget(lblJ3, 0, 4);
spinJoint3_ = new QDoubleSpinBox();
spinJoint3_->setRange(-180, 180);
spinJoint3_->setDecimals(2);
spinJoint3_->setValue(90);
jointLayout->addWidget(spinJoint3_, 0, 5);
QLabel* lblJ4 = new QLabel("J4:");
lblJ4->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
jointLayout->addWidget(lblJ4, 1, 0);
spinJoint4_ = new QDoubleSpinBox();
spinJoint4_->setRange(-180, 180);
spinJoint4_->setDecimals(2);
jointLayout->addWidget(spinJoint4_, 1, 1);
QLabel* lblJ5 = new QLabel("J5:");
lblJ5->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
jointLayout->addWidget(lblJ5, 1, 2);
spinJoint5_ = new QDoubleSpinBox();
spinJoint5_->setRange(-180, 180);
spinJoint5_->setDecimals(2);
spinJoint5_->setValue(45);
jointLayout->addWidget(spinJoint5_, 1, 3);
QLabel* lblJ6 = new QLabel("J6:");
lblJ6->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
jointLayout->addWidget(lblJ6, 1, 4);
spinJoint6_ = new QDoubleSpinBox();
spinJoint6_->setRange(-180, 180);
spinJoint6_->setDecimals(2);
jointLayout->addWidget(spinJoint6_, 1, 5);
// 按钮行
QHBoxLayout* jointBtnLayout = new QHBoxLayout();
btnMoveJJoint_ = new QPushButton("MoveJ 执行");
btnSyncJoint_ = new QPushButton("同步当前关节");
jointBtnLayout->addWidget(btnMoveJJoint_);
jointBtnLayout->addWidget(btnSyncJoint_);
jointBtnLayout->addStretch();
jointLayout->addLayout(jointBtnLayout, 2, 0, 1, 6);
motionLayout->addWidget(groupJoint);
// 运动控制按钮
QGroupBox* groupControl = new QGroupBox("运动控制", tabMotion);
QHBoxLayout* controlLayout = new QHBoxLayout(groupControl);
btnStop_ = new QPushButton("停止运动");
btnPause_ = new QPushButton("暂停运动");
btnResume_ = new QPushButton("恢复运动");
controlLayout->addWidget(btnStop_);
controlLayout->addWidget(btnPause_);
controlLayout->addWidget(btnResume_);
controlLayout->addStretch();
motionLayout->addWidget(groupControl);
tabWidget_->addTab(tabMotion, "运动控制");
// === Tab 2: 运动学 ===
QWidget* tabKin = new QWidget();
QVBoxLayout* kinLayout = new QVBoxLayout(tabKin);
// 正运动学
QGroupBox* groupFK = new QGroupBox("正运动学 (关节角度 -> TCP位姿)", tabKin);
QGridLayout* fkLayout = new QGridLayout(groupFK);
fkLayout->setHorizontalSpacing(5);
QLabel* lblFKJ1 = new QLabel("J1:");
lblFKJ1->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
fkLayout->addWidget(lblFKJ1, 0, 0);
spinFKJ1_ = new QDoubleSpinBox();
spinFKJ1_->setRange(-180, 180);
spinFKJ1_->setDecimals(2);
fkLayout->addWidget(spinFKJ1_, 0, 1);
QLabel* lblFKJ2 = new QLabel("J2:");
lblFKJ2->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
fkLayout->addWidget(lblFKJ2, 0, 2);
spinFKJ2_ = new QDoubleSpinBox();
spinFKJ2_->setRange(-180, 180);
spinFKJ2_->setDecimals(2);
spinFKJ2_->setValue(-45);
fkLayout->addWidget(spinFKJ2_, 0, 3);
QLabel* lblFKJ3 = new QLabel("J3:");
lblFKJ3->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
fkLayout->addWidget(lblFKJ3, 0, 4);
spinFKJ3_ = new QDoubleSpinBox();
spinFKJ3_->setRange(-180, 180);
spinFKJ3_->setDecimals(2);
spinFKJ3_->setValue(90);
fkLayout->addWidget(spinFKJ3_, 0, 5);
QLabel* lblFKJ4 = new QLabel("J4:");
lblFKJ4->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
fkLayout->addWidget(lblFKJ4, 1, 0);
spinFKJ4_ = new QDoubleSpinBox();
spinFKJ4_->setRange(-180, 180);
spinFKJ4_->setDecimals(2);
fkLayout->addWidget(spinFKJ4_, 1, 1);
QLabel* lblFKJ5 = new QLabel("J5:");
lblFKJ5->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
fkLayout->addWidget(lblFKJ5, 1, 2);
spinFKJ5_ = new QDoubleSpinBox();
spinFKJ5_->setRange(-180, 180);
spinFKJ5_->setDecimals(2);
spinFKJ5_->setValue(45);
fkLayout->addWidget(spinFKJ5_, 1, 3);
QLabel* lblFKJ6 = new QLabel("J6:");
lblFKJ6->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
fkLayout->addWidget(lblFKJ6, 1, 4);
spinFKJ6_ = new QDoubleSpinBox();
spinFKJ6_->setRange(-180, 180);
spinFKJ6_->setDecimals(2);
fkLayout->addWidget(spinFKJ6_, 1, 5);
btnForwardKin_ = new QPushButton("计算");
fkLayout->addWidget(btnForwardKin_, 0, 6, 2, 1);
fkLayout->addWidget(new QLabel("结果:"), 2, 0);
lblFKResult_ = new QLabel("--");
lblFKResult_->setWordWrap(true);
fkLayout->addWidget(lblFKResult_, 2, 1, 1, 6);
kinLayout->addWidget(groupFK);
// 逆运动学
QGroupBox* groupIK = new QGroupBox("逆运动学 (TCP位姿 -> 关节角度)", tabKin);
QGridLayout* ikLayout = new QGridLayout(groupIK);
ikLayout->setHorizontalSpacing(5);
QLabel* lblIKX = new QLabel("X:");
lblIKX->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
ikLayout->addWidget(lblIKX, 0, 0);
spinIKX_ = new QDoubleSpinBox();
spinIKX_->setRange(-2000, 2000);
spinIKX_->setDecimals(2);
spinIKX_->setValue(400);
ikLayout->addWidget(spinIKX_, 0, 1);
QLabel* lblIKY = new QLabel("Y:");
lblIKY->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
ikLayout->addWidget(lblIKY, 0, 2);
spinIKY_ = new QDoubleSpinBox();
spinIKY_->setRange(-2000, 2000);
spinIKY_->setDecimals(2);
ikLayout->addWidget(spinIKY_, 0, 3);
QLabel* lblIKZ = new QLabel("Z:");
lblIKZ->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
ikLayout->addWidget(lblIKZ, 0, 4);
spinIKZ_ = new QDoubleSpinBox();
spinIKZ_->setRange(-2000, 2000);
spinIKZ_->setDecimals(2);
spinIKZ_->setValue(300);
ikLayout->addWidget(spinIKZ_, 0, 5);
QLabel* lblIKRx = new QLabel("Rx:");
lblIKRx->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
ikLayout->addWidget(lblIKRx, 1, 0);
spinIKRx_ = new QDoubleSpinBox();
spinIKRx_->setRange(-180, 180);
spinIKRx_->setDecimals(2);
spinIKRx_->setValue(180);
ikLayout->addWidget(spinIKRx_, 1, 1);
QLabel* lblIKRy = new QLabel("Ry:");
lblIKRy->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
ikLayout->addWidget(lblIKRy, 1, 2);
spinIKRy_ = new QDoubleSpinBox();
spinIKRy_->setRange(-180, 180);
spinIKRy_->setDecimals(2);
ikLayout->addWidget(spinIKRy_, 1, 3);
QLabel* lblIKRz = new QLabel("Rz:");
lblIKRz->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
ikLayout->addWidget(lblIKRz, 1, 4);
spinIKRz_ = new QDoubleSpinBox();
spinIKRz_->setRange(-180, 180);
spinIKRz_->setDecimals(2);
ikLayout->addWidget(spinIKRz_, 1, 5);
btnInverseKin_ = new QPushButton("计算");
ikLayout->addWidget(btnInverseKin_, 0, 6, 2, 1);
ikLayout->addWidget(new QLabel("结果:"), 2, 0);
lblIKResult_ = new QLabel("--");
lblIKResult_->setWordWrap(true);
ikLayout->addWidget(lblIKResult_, 2, 1, 1, 6);
kinLayout->addWidget(groupIK);
tabWidget_->addTab(tabKin, "运动学");
middleLayout->addWidget(tabWidget_, 2);
// --- 右侧状态显示区(始终可见) ---
QWidget* statusWidget = new QWidget();
QVBoxLayout* statusMainLayout = new QVBoxLayout(statusWidget);
statusMainLayout->setContentsMargins(5, 0, 0, 0);
statusMainLayout->setSpacing(5);
// 关节状态
QGroupBox* groupJoints = new QGroupBox("关节位置 (deg)");
QGridLayout* jointsLayout = new QGridLayout(groupJoints);
jointsLayout->addWidget(new QLabel("J1:"), 0, 0);
lblJoint1_ = new QLabel("--");
lblJoint1_->setStyleSheet("font-weight: bold; color: #2196F3; min-width: 60px;");
jointsLayout->addWidget(lblJoint1_, 0, 1);
jointsLayout->addWidget(new QLabel("J2:"), 1, 0);
lblJoint2_ = new QLabel("--");
lblJoint2_->setStyleSheet("font-weight: bold; color: #2196F3; min-width: 60px;");
jointsLayout->addWidget(lblJoint2_, 1, 1);
jointsLayout->addWidget(new QLabel("J3:"), 2, 0);
lblJoint3_ = new QLabel("--");
lblJoint3_->setStyleSheet("font-weight: bold; color: #2196F3; min-width: 60px;");
jointsLayout->addWidget(lblJoint3_, 2, 1);
jointsLayout->addWidget(new QLabel("J4:"), 3, 0);
lblJoint4_ = new QLabel("--");
lblJoint4_->setStyleSheet("font-weight: bold; color: #2196F3; min-width: 60px;");
jointsLayout->addWidget(lblJoint4_, 3, 1);
jointsLayout->addWidget(new QLabel("J5:"), 4, 0);
lblJoint5_ = new QLabel("--");
lblJoint5_->setStyleSheet("font-weight: bold; color: #2196F3; min-width: 60px;");
jointsLayout->addWidget(lblJoint5_, 4, 1);
jointsLayout->addWidget(new QLabel("J6:"), 5, 0);
lblJoint6_ = new QLabel("--");
lblJoint6_->setStyleSheet("font-weight: bold; color: #2196F3; min-width: 60px;");
jointsLayout->addWidget(lblJoint6_, 5, 1);
statusMainLayout->addWidget(groupJoints);
// TCP 位姿
QGroupBox* groupTcp = new QGroupBox("TCP位姿 (mm/deg)");
QGridLayout* tcpLayout = new QGridLayout(groupTcp);
tcpLayout->addWidget(new QLabel("X:"), 0, 0);
lblTcpX_ = new QLabel("--");
lblTcpX_->setStyleSheet("font-weight: bold; color: #4CAF50; min-width: 60px;");
tcpLayout->addWidget(lblTcpX_, 0, 1);
tcpLayout->addWidget(new QLabel("Y:"), 1, 0);
lblTcpY_ = new QLabel("--");
lblTcpY_->setStyleSheet("font-weight: bold; color: #4CAF50; min-width: 60px;");
tcpLayout->addWidget(lblTcpY_, 1, 1);
tcpLayout->addWidget(new QLabel("Z:"), 2, 0);
lblTcpZ_ = new QLabel("--");
lblTcpZ_->setStyleSheet("font-weight: bold; color: #4CAF50; min-width: 60px;");
tcpLayout->addWidget(lblTcpZ_, 2, 1);
tcpLayout->addWidget(new QLabel("Rx:"), 3, 0);
lblTcpRx_ = new QLabel("--");
lblTcpRx_->setStyleSheet("font-weight: bold; color: #4CAF50; min-width: 60px;");
tcpLayout->addWidget(lblTcpRx_, 3, 1);
tcpLayout->addWidget(new QLabel("Ry:"), 4, 0);
lblTcpRy_ = new QLabel("--");
lblTcpRy_->setStyleSheet("font-weight: bold; color: #4CAF50; min-width: 60px;");
tcpLayout->addWidget(lblTcpRy_, 4, 1);
tcpLayout->addWidget(new QLabel("Rz:"), 5, 0);
lblTcpRz_ = new QLabel("--");
lblTcpRz_->setStyleSheet("font-weight: bold; color: #4CAF50; min-width: 60px;");
tcpLayout->addWidget(lblTcpRz_, 5, 1);
statusMainLayout->addWidget(groupTcp);
// 机器人状态
QGroupBox* groupRobotState = new QGroupBox("机器人状态");
QGridLayout* robotStateLayout = new QGridLayout(groupRobotState);
robotStateLayout->addWidget(new QLabel("状态:"), 0, 0);
lblRobotState_ = new QLabel("--");
robotStateLayout->addWidget(lblRobotState_, 0, 1);
robotStateLayout->addWidget(new QLabel("到位:"), 1, 0);
lblMotionDone_ = new QLabel("--");
robotStateLayout->addWidget(lblMotionDone_, 1, 1);
robotStateLayout->addWidget(new QLabel("错误:"), 2, 0);
lblErrorCode_ = new QLabel("--");
robotStateLayout->addWidget(lblErrorCode_, 2, 1);
statusMainLayout->addWidget(groupRobotState);
// 刷新控制
QHBoxLayout* refreshLayout = new QHBoxLayout();
btnRefreshState_ = new QPushButton("刷新");
btnAutoRefresh_ = new QPushButton("自动");
btnAutoRefresh_->setCheckable(true);
refreshLayout->addWidget(btnRefreshState_);
refreshLayout->addWidget(btnAutoRefresh_);
statusMainLayout->addLayout(refreshLayout);
statusWidget->setFixedWidth(160);
middleLayout->addWidget(statusWidget);
mainLayout->addLayout(middleLayout, 1);
// ========== 底部日志区 ==========
QGroupBox* groupLog = new QGroupBox("日志", this);
QVBoxLayout* logLayout = new QVBoxLayout(groupLog);
textLog_ = new QTextEdit();
textLog_->setReadOnly(true);
textLog_->setMaximumHeight(80);
logLayout->addWidget(textLog_);
mainLayout->addWidget(groupLog);
}
void MainWindow::setupConnections()
{
// 连接控制
connect(btnConnect_, &QPushButton::clicked, this, &MainWindow::onConnectClicked);
connect(btnDisconnect_, &QPushButton::clicked, this, &MainWindow::onDisconnectClicked);
connect(btnEnable_, &QPushButton::clicked, this, &MainWindow::onEnableClicked);
connect(btnDisable_, &QPushButton::clicked, this, &MainWindow::onDisableClicked);
connect(btnResetError_, &QPushButton::clicked, this, &MainWindow::onResetErrorClicked);
// 运动控制
connect(btnMoveL_, &QPushButton::clicked, this, &MainWindow::onMoveLClicked);
connect(btnMoveJPose_, &QPushButton::clicked, this, &MainWindow::onMoveJPoseClicked);
connect(btnMoveJJoint_, &QPushButton::clicked, this, &MainWindow::onMoveJJointClicked);
connect(btnStop_, &QPushButton::clicked, this, &MainWindow::onStopClicked);
connect(btnPause_, &QPushButton::clicked, this, &MainWindow::onPauseClicked);
connect(btnResume_, &QPushButton::clicked, this, &MainWindow::onResumeClicked);
// 同步按钮
connect(btnSyncPose_, &QPushButton::clicked, this, &MainWindow::onSyncPoseClicked);
connect(btnSyncJoint_, &QPushButton::clicked, this, &MainWindow::onSyncJointClicked);
// 状态刷新
connect(btnRefreshState_, &QPushButton::clicked, this, &MainWindow::onRefreshStateClicked);
connect(btnAutoRefresh_, &QPushButton::toggled, this, &MainWindow::onAutoRefreshToggled);
connect(refreshTimer_, &QTimer::timeout, this, &MainWindow::updateRobotState);
// 运动学
connect(btnForwardKin_, &QPushButton::clicked, this, &MainWindow::onForwardKinClicked);
connect(btnInverseKin_, &QPushButton::clicked, this, &MainWindow::onInverseKinClicked);
}
void MainWindow::log(const QString& msg)
{
QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
textLog_->append(QString("[%1] %2").arg(timestamp, msg));
}
void MainWindow::updateConnectionState(bool connected)
{
if (connected) {
lblConnectionStatus_->setText("已连接");
lblConnectionStatus_->setStyleSheet("color: green; font-weight: bold;");
} else {
lblConnectionStatus_->setText("未连接");
lblConnectionStatus_->setStyleSheet("color: red; font-weight: bold;");
}
btnConnect_->setEnabled(!connected);
btnDisconnect_->setEnabled(connected);
btnEnable_->setEnabled(connected);
btnDisable_->setEnabled(connected);
btnResetError_->setEnabled(connected);
btnMoveL_->setEnabled(connected);
btnMoveJPose_->setEnabled(connected);
btnMoveJJoint_->setEnabled(connected);
btnSyncPose_->setEnabled(connected);
btnSyncJoint_->setEnabled(connected);
btnStop_->setEnabled(connected);
btnPause_->setEnabled(connected);
btnResume_->setEnabled(connected);
btnRefreshState_->setEnabled(connected);
btnAutoRefresh_->setEnabled(connected);
btnForwardKin_->setEnabled(connected);
btnInverseKin_->setEnabled(connected);
}
// ========== 连接控制槽函数 ==========
void MainWindow::onConnectClicked()
{
QString ip = editIP_->text().trimmed();
log(QString("正在连接机器人: %1").arg(ip));
errno_t ret = robot_->Connect(ip.toStdString());
if (ret == ERR_SUCCESS) {
log("连接成功");
updateConnectionState(true);
updateRobotState();
} else {
log(QString("连接失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
updateConnectionState(false);
}
}
void MainWindow::onDisconnectClicked()
{
log("正在断开连接...");
robot_->Disconnect();
log("已断开连接");
updateConnectionState(false);
btnAutoRefresh_->setChecked(false);
}
void MainWindow::onEnableClicked()
{
errno_t ret = robot_->RobotEnable(1);
if (ret == ERR_SUCCESS) {
log("机器人已上使能");
} else {
log(QString("上使能失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onDisableClicked()
{
errno_t ret = robot_->RobotEnable(0);
if (ret == ERR_SUCCESS) {
log("机器人已下使能");
} else {
log(QString("下使能失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onResetErrorClicked()
{
errno_t ret = robot_->ResetAllError();
if (ret == ERR_SUCCESS) {
log("错误已清除");
} else {
log(QString("清除错误失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
// ========== 运动控制槽函数 ==========
void MainWindow::onMoveLClicked()
{
double x = spinPoseX_->value();
double y = spinPoseY_->value();
double z = spinPoseZ_->value();
double rx = spinPoseRx_->value();
double ry = spinPoseRy_->value();
double rz = spinPoseRz_->value();
float vel = spinVel_->value();
float acc = spinAcc_->value();
int tool = spinTool_->value();
int user = spinUser_->value();
log(QString("MoveL: X=%1, Y=%2, Z=%3, Rx=%4, Ry=%5, Rz=%6").arg(x).arg(y).arg(z).arg(rx).arg(ry).arg(rz));
errno_t ret = robot_->MoveL(x, y, z, rx, ry, rz, vel, acc, -1.0f, tool, user);
if (ret == ERR_SUCCESS) {
log("MoveL 指令已发送");
} else {
log(QString("MoveL 失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onMoveJPoseClicked()
{
double x = spinPoseX_->value();
double y = spinPoseY_->value();
double z = spinPoseZ_->value();
double rx = spinPoseRx_->value();
double ry = spinPoseRy_->value();
double rz = spinPoseRz_->value();
float vel = spinVel_->value();
float acc = spinAcc_->value();
int tool = spinTool_->value();
int user = spinUser_->value();
log(QString("MoveJ(Pose): X=%1, Y=%2, Z=%3, Rx=%4, Ry=%5, Rz=%6").arg(x).arg(y).arg(z).arg(rx).arg(ry).arg(rz));
errno_t ret = robot_->MoveJByPose(x, y, z, rx, ry, rz, vel, acc, -1.0f, tool, user);
if (ret == ERR_SUCCESS) {
log("MoveJ(Pose) 指令已发送");
} else {
log(QString("MoveJ(Pose) 失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onMoveJJointClicked()
{
double j1 = spinJoint1_->value();
double j2 = spinJoint2_->value();
double j3 = spinJoint3_->value();
double j4 = spinJoint4_->value();
double j5 = spinJoint5_->value();
double j6 = spinJoint6_->value();
float vel = spinVel_->value();
float acc = spinAcc_->value();
int tool = spinTool_->value();
int user = spinUser_->value();
log(QString("MoveJ(Joint): J1=%1, J2=%2, J3=%3, J4=%4, J5=%5, J6=%6").arg(j1).arg(j2).arg(j3).arg(j4).arg(j5).arg(j6));
errno_t ret = robot_->MoveJByJoint(j1, j2, j3, j4, j5, j6, vel, acc, -1.0f, tool, user);
if (ret == ERR_SUCCESS) {
log("MoveJ(Joint) 指令已发送");
} else {
log(QString("MoveJ(Joint) 失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onStopClicked()
{
errno_t ret = robot_->StopMotion();
if (ret == ERR_SUCCESS) {
log("运动已停止");
} else {
log(QString("停止失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onPauseClicked()
{
errno_t ret = robot_->PauseMotion();
if (ret == ERR_SUCCESS) {
log("运动已暂停");
} else {
log(QString("暂停失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onResumeClicked()
{
errno_t ret = robot_->ResumeMotion();
if (ret == ERR_SUCCESS) {
log("运动已恢复");
} else {
log(QString("恢复失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
// ========== 同步位置槽函数 ==========
void MainWindow::onSyncPoseClicked()
{
double x, y, z, rx, ry, rz;
if (robot_->GetCurrentTCPPose(x, y, z, rx, ry, rz) == ERR_SUCCESS) {
spinPoseX_->setValue(x);
spinPoseY_->setValue(y);
spinPoseZ_->setValue(z);
spinPoseRx_->setValue(rx);
spinPoseRy_->setValue(ry);
spinPoseRz_->setValue(rz);
log("已同步当前位姿到输入框");
} else {
log(QString("获取位姿失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onSyncJointClicked()
{
double j1, j2, j3, j4, j5, j6;
if (robot_->GetCurrentJointPos(j1, j2, j3, j4, j5, j6) == ERR_SUCCESS) {
spinJoint1_->setValue(j1);
spinJoint2_->setValue(j2);
spinJoint3_->setValue(j3);
spinJoint4_->setValue(j4);
spinJoint5_->setValue(j5);
spinJoint6_->setValue(j6);
log("已同步当前关节到输入框");
} else {
log(QString("获取关节失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
// ========== 状态刷新槽函数 ==========
void MainWindow::onRefreshStateClicked()
{
updateRobotState();
}
void MainWindow::onAutoRefreshToggled(bool checked)
{
if (checked) {
refreshTimer_->start(200); // 200ms 刷新一次
log("自动刷新已开启");
} else {
refreshTimer_->stop();
log("自动刷新已关闭");
}
}
void MainWindow::updateRobotState()
{
if (!robot_->IsConnected()) return;
// 获取关节位置
double j1, j2, j3, j4, j5, j6;
if (robot_->GetCurrentJointPos(j1, j2, j3, j4, j5, j6) == ERR_SUCCESS) {
lblJoint1_->setText(QString::number(j1, 'f', 2));
lblJoint2_->setText(QString::number(j2, 'f', 2));
lblJoint3_->setText(QString::number(j3, 'f', 2));
lblJoint4_->setText(QString::number(j4, 'f', 2));
lblJoint5_->setText(QString::number(j5, 'f', 2));
lblJoint6_->setText(QString::number(j6, 'f', 2));
}
// 获取TCP位姿
double x, y, z, rx, ry, rz;
if (robot_->GetCurrentTCPPose(x, y, z, rx, ry, rz) == ERR_SUCCESS) {
lblTcpX_->setText(QString::number(x, 'f', 2));
lblTcpY_->setText(QString::number(y, 'f', 2));
lblTcpZ_->setText(QString::number(z, 'f', 2));
lblTcpRx_->setText(QString::number(rx, 'f', 2));
lblTcpRy_->setText(QString::number(ry, 'f', 2));
lblTcpRz_->setText(QString::number(rz, 'f', 2));
}
// 获取运动状态
uint8_t motionDone;
if (robot_->GetMotionDone(motionDone) == ERR_SUCCESS) {
lblMotionDone_->setText(motionDone ? "" : "");
}
// 获取错误码
int maincode, subcode;
if (robot_->GetErrorCode(maincode, subcode) == ERR_SUCCESS) {
lblErrorCode_->setText(QString("%1/%2").arg(maincode).arg(subcode));
if (maincode != 0) {
lblErrorCode_->setStyleSheet("color: red; font-weight: bold;");
} else {
lblErrorCode_->setStyleSheet("color: green;");
}
}
// 获取机器人状态
ROBOT_STATE_PKG state;
if (robot_->GetRobotState(state) == ERR_SUCCESS) {
QString stateStr;
switch (state.robot_state) {
case 1: stateStr = "停止"; break;
case 2: stateStr = "运行"; break;
case 3: stateStr = "暂停"; break;
case 4: stateStr = "拖动"; break;
default: stateStr = QString("未知(%1)").arg(state.robot_state);
}
lblRobotState_->setText(stateStr);
}
}
// ========== 运动学槽函数 ==========
void MainWindow::onForwardKinClicked()
{
double j1 = spinFKJ1_->value();
double j2 = spinFKJ2_->value();
double j3 = spinFKJ3_->value();
double j4 = spinFKJ4_->value();
double j5 = spinFKJ5_->value();
double j6 = spinFKJ6_->value();
double x, y, z, rx, ry, rz;
errno_t ret = robot_->ForwardKinematics(j1, j2, j3, j4, j5, j6, x, y, z, rx, ry, rz);
if (ret == ERR_SUCCESS) {
lblFKResult_->setText(QString("X=%1, Y=%2, Z=%3, Rx=%4, Ry=%5, Rz=%6")
.arg(x, 0, 'f', 2).arg(y, 0, 'f', 2).arg(z, 0, 'f', 2)
.arg(rx, 0, 'f', 2).arg(ry, 0, 'f', 2).arg(rz, 0, 'f', 2));
log("正运动学计算完成");
} else {
lblFKResult_->setText(QString("计算失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}
void MainWindow::onInverseKinClicked()
{
double x = spinIKX_->value();
double y = spinIKY_->value();
double z = spinIKZ_->value();
double rx = spinIKRx_->value();
double ry = spinIKRy_->value();
double rz = spinIKRz_->value();
double j1, j2, j3, j4, j5, j6;
errno_t ret = robot_->InverseKinematics(x, y, z, rx, ry, rz, j1, j2, j3, j4, j5, j6);
if (ret == ERR_SUCCESS) {
lblIKResult_->setText(QString("J1=%1, J2=%2, J3=%3, J4=%4, J5=%5, J6=%6")
.arg(j1, 0, 'f', 2).arg(j2, 0, 'f', 2).arg(j3, 0, 'f', 2)
.arg(j4, 0, 'f', 2).arg(j5, 0, 'f', 2).arg(j6, 0, 'f', 2));
log("逆运动学计算完成");
} else {
lblIKResult_->setText(QString("计算失败: %1").arg(QString::fromStdString(robot_->GetLastErrorString())));
}
}