From 98d1efa5ef8ab3911e8700696d19a9f4e8bf7dbc Mon Sep 17 00:00:00 2001 From: yiyi Date: Mon, 23 Mar 2026 09:17:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=8B=E7=9C=BC=E6=A0=87=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tools/CalibView/CalibView.pro | 2 +- Tools/CalibView/Inc/CalibViewMainWindow.h | 12 +++- Tools/CalibView/Src/CalibViewMainWindow.cpp | 78 ++++++++++++++++----- 3 files changed, 74 insertions(+), 18 deletions(-) diff --git a/Tools/CalibView/CalibView.pro b/Tools/CalibView/CalibView.pro index 2e12a2ae..90619a9f 100644 --- a/Tools/CalibView/CalibView.pro +++ b/Tools/CalibView/CalibView.pro @@ -1,7 +1,7 @@ # CalibView - 手眼标定工具 QT += core gui widgets -CONFIG += c++17 console +CONFIG += c++17 #console CONFIG -= app_bundle # Windows平台UTF-8编码支持 diff --git a/Tools/CalibView/Inc/CalibViewMainWindow.h b/Tools/CalibView/Inc/CalibViewMainWindow.h index 41f4e38a..257a7194 100644 --- a/Tools/CalibView/Inc/CalibViewMainWindow.h +++ b/Tools/CalibView/Inc/CalibViewMainWindow.h @@ -36,10 +36,20 @@ signals: private slots: /** - * @brief 执行 Eye-To-Hand 标定 + * @brief 执行 Eye-To-Hand 标定(选择方法) */ void onEyeToHandCalib(); + /** + * @brief 执行 Eye-To-Hand 标定(简单方法 - 仅位置) + */ + void onEyeToHandCalibSimple(); + + /** + * @brief 执行 Eye-To-Hand 标定(完整位姿方法 - Park算法) + */ + void onEyeToHandCalibWithPose(); + /** * @brief 执行 Eye-In-Hand 标定 */ diff --git a/Tools/CalibView/Src/CalibViewMainWindow.cpp b/Tools/CalibView/Src/CalibViewMainWindow.cpp index bfaed788..ecd4744a 100644 --- a/Tools/CalibView/Src/CalibViewMainWindow.cpp +++ b/Tools/CalibView/Src/CalibViewMainWindow.cpp @@ -48,7 +48,7 @@ CalibViewMainWindow::CalibViewMainWindow(QWidget* parent) createMenuBar(); SpinBoxPasteHelper::install(this); - setWindowTitle("CalibView - 手眼标定工具"); + setWindowTitle("CalibView - 手眼标定工具 - 1.0.0"); resize(1400, 700); updateStatusBar("就绪"); @@ -303,10 +303,61 @@ void CalibViewMainWindow::onEyeToHandCalib() return; } - // 使用完整位姿方法(Park 方法) + QMessageBox msgBox(this); + msgBox.setWindowTitle("选择标定方法"); + msgBox.setText("请选择 Eye-To-Hand 标定方法:"); + QPushButton* simpleBtn = msgBox.addButton("简单方法 (仅位置)", QMessageBox::ActionRole); + QPushButton* poseBtn = msgBox.addButton("完整位姿方法 (Park算法)", QMessageBox::ActionRole); + QPushButton* cancelBtn = msgBox.addButton("取消", QMessageBox::RejectRole); + + msgBox.exec(); + + if (msgBox.clickedButton() == cancelBtn) { + return; + } + + if (msgBox.clickedButton() == simpleBtn) { + onEyeToHandCalibSimple(); + } else if (msgBox.clickedButton() == poseBtn) { + onEyeToHandCalibWithPose(); + } +} + +void CalibViewMainWindow::onEyeToHandCalibSimple() +{ + appendLog("开始 Eye-To-Hand 标定(简单方法 - 仅位置)..."); + + std::vector eyePoints; + std::vector robotPoints; + m_dataWidget->getEyeToHandData(eyePoints, robotPoints); + + if (eyePoints.size() < 3) { + QMessageBox::warning(this, "警告", "至少需要3组数据进行标定"); + return; + } + + appendLog(QString("输入数据组数: %1").arg(eyePoints.size())); + appendLog("使用 SVD 分解方法,仅利用位置信息"); + + int ret = m_calib->CalculateRT(eyePoints, robotPoints, m_currentResult); + + if (ret == 0) { + m_hasResult = true; + m_resultWidget->showCalibResult(m_currentResult); + appendLog(QString("标定成功,误差: %1 mm") + .arg(m_currentResult.error, 0, 'f', 4)); + updateStatusBar("Eye-To-Hand 标定完成(简单方法)"); + emit calibrationCompleted(m_currentResult); + } else { + appendLog(QString("标定失败,错误码: %1").arg(ret)); + QMessageBox::critical(this, "错误", QString("标定失败,错误码: %1").arg(ret)); + } +} + +void CalibViewMainWindow::onEyeToHandCalibWithPose() +{ appendLog("开始 Eye-To-Hand 标定(完整位姿方法 - Park 算法)..."); - // 从 CalibDataWidget 获取完整位姿数据 std::vector calibData; m_dataWidget->getEyeToHandPoseData(calibData); @@ -317,7 +368,6 @@ void CalibViewMainWindow::onEyeToHandCalib() return; } - // 获取欧拉角顺序 HECEulerOrder eulerOrder = m_dataWidget->getEulerOrder(); QString eulerOrderStr; switch (eulerOrder) { @@ -572,12 +622,18 @@ void CalibViewMainWindow::onSaveResult() // [CommInfo] ini.beginGroup("CommInfo"); - ini.setValue("sCalibTime", QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")); - ini.setValue("dError", m_currentResult.error); + ini.setValue("nMaxMaxMatrixNum", 8); + ini.setValue("nExistMatrixNum", 1); ini.endGroup(); // [CalibMatrixInfo_0] - 4x4 齐次矩阵 ini.beginGroup("CalibMatrixInfo_0"); + ini.setValue("sCalibTime", QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")); + ini.setValue("nCalibPosIdx", 0); + ini.setValue("nCalibType", 0); + ini.setValue("nCalibMode", 0); + ini.setValue("sCalibPosName", 0); + ini.setValue("dError", m_currentResult.error); // 第0行: R[0,0] R[0,1] R[0,2] Tx ini.setValue("dCalibMatrix_0", m_currentResult.R.data[0]); ini.setValue("dCalibMatrix_1", m_currentResult.R.data[1]); @@ -600,16 +656,6 @@ void CalibViewMainWindow::onSaveResult() ini.setValue("dCalibMatrix_15", 1.0); ini.endGroup(); - // [CenterInfo] - 质心 - ini.beginGroup("CenterInfo"); - ini.setValue("dCenterEyeX", m_currentResult.centerEye.x); - ini.setValue("dCenterEyeY", m_currentResult.centerEye.y); - ini.setValue("dCenterEyeZ", m_currentResult.centerEye.z); - ini.setValue("dCenterRobotX", m_currentResult.centerRobot.x); - ini.setValue("dCenterRobotY", m_currentResult.centerRobot.y); - ini.setValue("dCenterRobotZ", m_currentResult.centerRobot.z); - ini.endGroup(); - appendLog(QString("结果已保存到: %1").arg(fileName)); updateStatusBar("结果已保存"); }