From 496f61c0e1ef3bd0d95ce7d269ac5933ea7c414e Mon Sep 17 00:00:00 2001 From: tangchao0503 <735056338@qq.com> Date: Fri, 12 Sep 2025 16:21:42 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=96=B0=E7=9A=84=E4=BA=8C?= =?UTF-8?q?=E8=BD=B4=E9=87=87=E9=9B=86=EF=BC=9A=E4=BA=8C=E8=BD=B4=E9=87=87?= =?UTF-8?q?=E9=9B=86=E9=80=BB=E8=BE=91=E6=8E=A7=E5=88=B6=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HPPA/CaptureCoordinator.cpp | 443 +++++++++++++++ HPPA/CaptureCoordinator.h | 107 ++++ HPPA/HPPA.cpp | 81 ++- HPPA/HPPA.h | 7 +- HPPA/HPPA.ui | 149 ++++- HPPA/ImagerOperationBase.cpp | 19 +- HPPA/ImagerOperationBase.h | 3 +- HPPA/ResononNirImager.cpp | 10 +- HPPA/TwoMotorControl.cpp | 581 +++++++++++++++++++ HPPA/TwoMotorControl.h | 89 +++ HPPA/twoMotorControl.ui | 1010 ++++++++++++++++++++++++++++++++++ 11 files changed, 2469 insertions(+), 30 deletions(-) create mode 100644 HPPA/CaptureCoordinator.cpp create mode 100644 HPPA/CaptureCoordinator.h create mode 100644 HPPA/TwoMotorControl.cpp create mode 100644 HPPA/TwoMotorControl.h create mode 100644 HPPA/twoMotorControl.ui diff --git a/HPPA/CaptureCoordinator.cpp b/HPPA/CaptureCoordinator.cpp new file mode 100644 index 0000000..8abec83 --- /dev/null +++ b/HPPA/CaptureCoordinator.cpp @@ -0,0 +1,443 @@ +#include "CaptureCoordinator.h" + +TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator( + IrisMultiMotorController* motorCtrl, + ImagerOperationBase* cameraCtrl, + QObject* parent) + : QObject(parent) + , m_motorCtrl(motorCtrl) + , m_cameraCtrl(cameraCtrl) + , m_isRunning(false) +{ + //这些信号槽是按照逻辑顺序的 + connect(this, SIGNAL(moveTo(int, double, double, int)), + m_motorCtrl, SLOT(moveTo(int, double, double, int))); + connect(this, SIGNAL(moveTo(const std::vector, const std::vector, int)), + m_motorCtrl, SLOT(moveTo(const std::vector, const std::vector, int))); + connect(this, &TwoMotionCaptureCoordinator::stopMotorSignal, m_motorCtrl, &IrisMultiMotorController::stop); + + connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, + this, &TwoMotionCaptureCoordinator::handlePositionReached); + //connect(m_motorCtrl, &IrisMultiMotorController::moveFailed, + // this, &TwoMotionCaptureCoordinator::handleError); + + connect(this, &TwoMotionCaptureCoordinator::startRecordHSISignal, + m_cameraCtrl, &ImagerOperationBase::start_record); + connect(this, &TwoMotionCaptureCoordinator::stopRecordHSISignal, + m_cameraCtrl, &ImagerOperationBase::stop_record); + connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberMeet, + this, &TwoMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet); + //connect(m_cameraCtrl, &ImagerOperationBase::RecordFinishedSignal_WhenFrameNumberNotMeet, + // this, &TwoMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberNotMeet); + //connect(m_cameraCtrl, &ImagerOperationBase::captureFailed, + // this, &TwoMotionCaptureCoordinator::handleError); +} + +TwoMotionCaptureCoordinator::TwoMotionCaptureCoordinator( + IrisMultiMotorController* motorCtrl, + QObject* parent) + : QObject(parent) + , m_motorCtrl(motorCtrl) + , m_isRunning(false) +{ + connect(this, SIGNAL(moveTo(int, double, double, int)), + m_motorCtrl, SLOT(moveTo(int, double, double, int))); + connect(this, SIGNAL(moveTo(const std::vector, const std::vector, int)), + m_motorCtrl, SLOT(moveTo(const std::vector, const std::vector, int))); + + connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, + this, &TwoMotionCaptureCoordinator::handlePositionReached); + //connect(m_motorCtrl, &IrisMultiMotorController::moveFailed, + // this, &TwoMotionCaptureCoordinator::handleError); +} + +TwoMotionCaptureCoordinator::~TwoMotionCaptureCoordinator() +{ + +} + +void TwoMotionCaptureCoordinator::start(QVector pathLines) +{ + //QMutexLocker locker(&m_dataMutex); + + if (m_isRunning) + { + emit errorOccurred("Sequence already running"); + std::cout << "already running" << std::endl; + return; + } + + getLocBeforeStart(); + + m_pathLines = pathLines; + + m_isMoving2XMin = false; + m_isMoving2XMax = false; + m_isMoving2XStartLoc = false; + + m_isMoving2YTargeLoc = false; + m_isMoving2YStartLoc = false; + m_isImagerFrameNumberMeet = false; + + m_retryTimesMoving2XMin = 0; + m_retryTimesMoving2XMax = 0; + m_retryTimesMoving2YTargeLoc = 0; + + m_isRunning = true; + m_numCurrentPathLine = 0; + processNextPathLine(); +} + +void TwoMotionCaptureCoordinator::stop() +{ + if (!m_isRunning) return; + + //QMutexLocker locker(&m_dataMutex); + + std::cout << "The user manually stops the collection! " << std::endl; + savePathLinesToCsv(); + + emit sequenceComplete(1); + emit finishRecordLineNumSignal(m_numCurrentPathLine); + //emit stopRecordHSISignal(m_numCurrentPathLine); + if (m_cameraCtrl != nullptr) + { + m_cameraCtrl->stop_record(); + } + + move2LocBeforeStart(); +} + +void TwoMotionCaptureCoordinator::getLocBeforeStart() +{ + QEventLoop loop; + bool received = false; + + QTimer timer; + timer.setSingleShot(true); + connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + + QMetaObject::Connection conn = QObject::connect(m_motorCtrl, &IrisMultiMotorController::locationSignal, + [&](std::vector pos) { + m_locBeforeStart = pos; + received = true; + loop.quit(); + }); + + QMetaObject::invokeMethod(m_motorCtrl, "getLoc", Qt::QueuedConnection); + timer.start(3000); + + loop.exec(); + + disconnect(conn); +} + +void TwoMotionCaptureCoordinator::getRecordState() +{ + emit recordState(m_isRunning); +} + +void TwoMotionCaptureCoordinator::move2LocBeforeStart() +{ + std::cout << "\nmove2LocBeforeStart." << std::endl; + + PathLine& tmp = m_pathLines[0]; + std::vector speed; + speed.push_back(tmp.speedTargetXMinPosition); + speed.push_back(tmp.speedTargetYPosition); + emit moveTo(m_locBeforeStart, speed, 1000); + + m_isRunning = false; + + m_isMoving2XMin = false; + m_isMoving2XMax = false; + m_isMoving2YTargeLoc = false; + + m_isMoving2XStartLoc = true; + m_isMoving2YStartLoc = true; +} + +QVector TwoMotionCaptureCoordinator::pathLines() const +{ + //QMutexLocker locker(&m_dataMutex); + return m_pathLines; +} + +double TwoMotionCaptureCoordinator::getTimeDiffMinutes(QDateTime startTime, QDateTime endTime) +{ + qint64 diffMillis = startTime.msecsTo(endTime); + double diffMinutes = (double)diffMillis / 60000;//min + + return diffMinutes; +} + +bool TwoMotionCaptureCoordinator::savePathLinesToCsv(QString filename) +{ + //QMutexLocker locker(&m_dataMutex); + if (filename.isEmpty()) + { + FileOperation* fileOperation = new FileOperation(); + string directory = fileOperation->getDirectoryOfExe(); + QDateTime now = QDateTime::currentDateTime(); + QString format1 = "yyyyMMdd_HHmmss"; + QString fileNameTmp = now.toString("yyyyMMdd_HHmmss"); + + filename = QDir::cleanPath(QString::fromStdString(directory) + QDir::separator() + "pathLines" + QDir::separator() + fileNameTmp + "_pathLines.csv"); + } + + QDir dir = QFileInfo(filename).absoluteDir(); + + // 如果目录不存在,则递归创建 + if (!dir.exists()) { + if (!dir.mkpath(".")) { + qWarning() << "Failed to create directory:" << dir.path(); + return false; + } + } + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + return false; + } + + QTextStream out(&file); + out << "timestamp1,timestamp2,timestamp3,time consuming(min),targetYPosition,actualYPosition,targetXMinPosition,actualXMinPosition,targetXMaxPosition,actualXMaxPosition\n"; + + for (const auto& data : m_pathLines) + { + out << data.timestamp1.toString("yyyy-MM-dd HH:mm:ss.zzz") << "," + << data.timestamp2.toString("yyyy-MM-dd HH:mm:ss.zzz") << "," + << data.timestamp3.toString("yyyy-MM-dd HH:mm:ss.zzz") << "," + << QString::number(getTimeDiffMinutes(data.timestamp2, data.timestamp3), 'f', 4) << "," + << QString::number(data.targetYPosition, 'f', 4) << "," + << QString::number(data.actualYPosition, 'f', 4) << "," + << QString::number(data.targetXMinPosition, 'f', 4) << "," + << QString::number(data.actualXMinPosition, 'f', 4) << "," + << QString::number(data.targetXMaxPosition, 'f', 4) << "," + << QString::number(data.actualXMaxPosition, 'f', 4) + << "\n"; + } + + file.close(); + return true; +} + +void TwoMotionCaptureCoordinator::handlePositionReached(int motorID, double pos) +{ + if (!m_isRunning) return; + + //QMutexLocker locker(&m_dataMutex); + + PathLine &tmp = m_pathLines[m_numCurrentPathLine]; + + if (motorID == 1)//y马达 + { + if (m_isMoving2YTargeLoc) + { + double threshold = getThre(tmp.targetYPosition, pos); + + if (threshold > 5) + { + //没到准确位置,再次给马达发送命令 + if (m_retryTimesMoving2YTargeLoc < m_retryLimit) + { + m_retryTimesMoving2YTargeLoc++; + + std::cout << "Y motor Moving2YTargeLoc error. Retry..." << std::endl; + emit moveTo(1, tmp.targetYPosition, tmp.speedTargetYPosition, 1000); + return; + } + } + m_retryTimesMoving2YTargeLoc = 0; + + tmp.actualYPosition = pos; + + m_isMoving2YTargeLoc = false; + + std::cout << "y motor is reached!!!! " << std::endl; + startRecordHsi(); + + return; + } + + if (m_isMoving2YStartLoc) + { + m_isMoving2YStartLoc = false; + + return; + } + } + if (motorID == 0)//x马达 + { + if (m_isMoving2XMin) + { + double threshold = getThre(tmp.targetXMinPosition, pos); + + if (threshold > 5) + { + //没到准确位置,再次给马达发送命令 + if (m_retryTimesMoving2XMin < m_retryLimit) + { + m_retryTimesMoving2XMin++; + + std::cout << "X motor Moving2XMin error. Retry..." << std::endl; + emit moveTo(0, tmp.targetXMinPosition, tmp.speedTargetXMinPosition, 1000); + return; + } + } + m_retryTimesMoving2XMin = 0; + + tmp.actualXMinPosition = pos; + + m_isMoving2XMin = false; + + std::cout << "x motor is reached!!!! " << std::endl; + startRecordHsi(); + + return; + } + + if (m_isMoving2XMax) + { + double threshold = getThre(tmp.targetXMaxPosition, pos); + + if (threshold > 5 && !m_isImagerFrameNumberMeet)//马达没到准确位置 && 【非】光谱仪因帧数限制主动停止采集 + { + //没到准确位置,再次给马达发送命令 + if (m_retryTimesMoving2XMax < m_retryLimit) + { + m_retryTimesMoving2XMax++; + + std::cout << "X motor Moving2XMax error. Retry..." << std::endl; + emit moveTo(0, tmp.targetXMaxPosition, tmp.speedTargetXMaxPosition, 1000); + return; + } + } + m_retryTimesMoving2XMax = 0; + + tmp.actualXMaxPosition = pos; + tmp.timestamp3 = QDateTime::currentDateTime(); + + std::cout << "Line " << m_numCurrentPathLine << " time span(min):" << getTimeDiffMinutes(tmp.timestamp2, tmp.timestamp3) << std::endl; + + //停止采集高光谱数据 + emit finishRecordLineNumSignal(m_numCurrentPathLine); + //emit stopRecordHSISignal(m_numCurrentPathLine); + if (m_cameraCtrl!=nullptr) + { + m_cameraCtrl->stop_record(); + } + + m_isMoving2XMax = false; + m_isImagerFrameNumberMeet = false; + m_numCurrentPathLine++; + processNextPathLine(); + + return; + } + + if (m_isMoving2XStartLoc) + { + m_isMoving2XStartLoc = false; + + return; + } + } +} + +double TwoMotionCaptureCoordinator::getThre(double targetLoc,double actualLoc) +{ + double targetLocTmp; + if (targetLoc == 0) + { + targetLocTmp = 0.001; + } + else + { + targetLocTmp = targetLoc; + } + double thre = abs(targetLoc - actualLoc) / targetLocTmp * 100; + + return thre; +} + +void TwoMotionCaptureCoordinator::startRecordHsi() +{ + if (!m_isRunning) return; + + //QMutexLocker locker(&m_dataMutex); + + if (!m_isMoving2XMin && !m_isMoving2YTargeLoc) + { + //开始采集高光谱数据 + PathLine &tmp = m_pathLines[m_numCurrentPathLine]; + tmp.timestamp2 = QDateTime::currentDateTime(); + std::cout << "start recording hsi, moving to " << tmp.targetXMaxPosition << std::endl; + + m_isMoving2XMax = true; + emit moveTo(0, tmp.targetXMaxPosition, tmp.speedTargetXMaxPosition, 1000); + + emit startRecordHSISignal(m_numCurrentPathLine); + } +} + +void TwoMotionCaptureCoordinator::handleCaptureCompleteWhenFrameNumberMeet() +{ + m_isImagerFrameNumberMeet = true; + emit stopMotorSignal(0); +} + +void TwoMotionCaptureCoordinator::handleError(const QString& error) +{ + //QMutexLocker locker(&m_dataMutex); + m_isRunning = false; + emit errorOccurred(error); +} + +void TwoMotionCaptureCoordinator::processNextPathLine() +{ + if (!m_isRunning) return; + + int numPathLines = m_pathLines.size(); + + if (numPathLines == 0) + { + move2LocBeforeStart(); + return; + } + + if (m_isMoving2YTargeLoc || m_isMoving2XMin) + { + return; + } + + if (m_numCurrentPathLine > numPathLines - 1) + { + std::cout << "\nAll path lines is finished! " << std::endl; + + move2LocBeforeStart(); + savePathLinesToCsv(); + + emit sequenceComplete(0); + + return; + } + + std::cout << "\nNew path line: " << m_numCurrentPathLine << std::endl; + emit startRecordLineNumSignal(m_numCurrentPathLine); + + PathLine &tmp = m_pathLines[m_numCurrentPathLine]; + tmp.timestamp1 = QDateTime::currentDateTime(); + + std::vector loc; + loc.push_back(tmp.targetXMinPosition); + loc.push_back(tmp.targetYPosition); + std::vector speed; + speed.push_back(tmp.speedTargetXMinPosition); + speed.push_back(tmp.speedTargetYPosition); + + m_isMoving2YTargeLoc = true; + m_isMoving2XMin = true; + emit moveTo(loc, speed, 1000); +} diff --git a/HPPA/CaptureCoordinator.h b/HPPA/CaptureCoordinator.h new file mode 100644 index 0000000..ebeb60a --- /dev/null +++ b/HPPA/CaptureCoordinator.h @@ -0,0 +1,107 @@ +#pragma once +#include +#include +#include +#include + +#include "ImagerOperationBase.h" +#include "IrisMultiMotorController.h" + +struct PathLine +{ + double targetYPosition; + double actualYPosition; + double speedTargetYPosition; + + double targetXMinPosition; + double actualXMinPosition; + double speedTargetXMinPosition; + + double targetXMaxPosition; + double actualXMaxPosition; + double speedTargetXMaxPosition; + + QDateTime timestamp1;//开始航线 + QDateTime timestamp2;//开始采集高光谱 + QDateTime timestamp3;//结束采集高光谱 + + PathLine(double targetYPosition_=0, double targetXMinPosition_ = 0, double targetXMaxPosition_ = 0) + : targetYPosition(targetYPosition_), actualYPosition(0), speedTargetYPosition(0), + targetXMinPosition(targetXMinPosition_), actualXMinPosition(0), speedTargetXMinPosition(0), + targetXMaxPosition(targetXMaxPosition_), actualXMaxPosition(0), speedTargetXMaxPosition(0), + timestamp1(QDateTime::currentDateTime()), timestamp2(QDateTime::currentDateTime()), timestamp3(QDateTime::currentDateTime()) {} +}; +Q_DECLARE_METATYPE(PathLine); +//Q_DECLARE_METATYPE(QVector); + +class TwoMotionCaptureCoordinator : public QObject +{ + Q_OBJECT +public: + TwoMotionCaptureCoordinator(IrisMultiMotorController* motorCtrl, + ImagerOperationBase* cameraCtrl, + QObject* parent = nullptr); + TwoMotionCaptureCoordinator(IrisMultiMotorController* motorCtrl, + QObject* parent = nullptr); + ~TwoMotionCaptureCoordinator(); + + QVector pathLines() const; + +signals: + void sequenceComplete(int);//0:所有采集线正常运行完成,1:用户主动取消采集 + void startRecordLineNumSignal(int lineNum); + void finishRecordLineNumSignal(int lineNum); + + void startRecordHSISignal(int lineNum); + void stopRecordHSISignal(int lineNum); + + void errorOccurred(const QString& error); + void moveTo(int, double, double, int); + void moveTo(const std::vector, const std::vector, int); + void stopMotorSignal(int axis); + + void recordState(bool state); + +private slots: + void start(QVector pathLines); + void stop(); + void getRecordState(); + + void handlePositionReached(int motorID, double pos); + void handleCaptureCompleteWhenFrameNumberMeet(); + void handleError(const QString& error); + + void move2LocBeforeStart(); + +private: + void processNextPathLine(); + void startRecordHsi(); + void getLocBeforeStart(); + double getThre(double targetLoc, double actualLoc); + + double getTimeDiffMinutes(QDateTime startTime, QDateTime endTime); + bool savePathLinesToCsv(QString filename= QString()); + + IrisMultiMotorController* m_motorCtrl; + ImagerOperationBase* m_cameraCtrl=nullptr; + QVector m_pathLines; + mutable QMutex m_dataMutex; + + bool m_isRunning; + bool m_isMoving2YTargeLoc; + bool m_isMoving2XMin; + bool m_isMoving2XMax; + + int m_retryLimit = 3; + int m_retryTimesMoving2YTargeLoc; + int m_retryTimesMoving2XMin; + int m_retryTimesMoving2XMax; + + bool m_isImagerFrameNumberMeet;//光谱仪帧数限制到了,主动停止采集 + std::vector m_locBeforeStart; + + bool m_isMoving2XStartLoc; + bool m_isMoving2YStartLoc; + + int m_numCurrentPathLine; +}; diff --git a/HPPA/HPPA.cpp b/HPPA/HPPA.cpp index 95ad4d7..d85aa6e 100644 --- a/HPPA/HPPA.cpp +++ b/HPPA/HPPA.cpp @@ -311,6 +311,18 @@ HPPA::HPPA(QWidget *parent) tabifyDockWidget(dock_rac, dock_omc); mPanelMenu->addAction(dock_omc->toggleViewAction()); + //2 + tmc = new TwoMotorControl(this); + connect(tmc, SIGNAL(startLineNumSignal(int)), this, SLOT(onCreateTab(int))); + connect(tmc, SIGNAL(sequenceComplete()), this, SLOT(onsequenceComplete())); + dock_tmc = new QDockWidget(QString::fromLocal8Bit("2"), this); + dock_tmc->setObjectName("mDockTwoMotorControl"); + dock_tmc->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + dock_tmc->setWidget(tmc); + tabifyDockWidget(dock_omc, dock_tmc); + mPanelMenu->addAction(dock_tmc->toggleViewAction()); + + createActionGroups(); connect(mImagerGroup, &QActionGroup::triggered, this, &HPPA::selectingImager); @@ -363,7 +375,6 @@ void HPPA::recordFromRobotArm(int fileCounter) } onCreateTab(fileCounter-1); - m_numberOfRecording = fileCounter - 1; emit StartRecordSignal(); ui.action_start_recording->setText(QString::fromLocal8Bit("ɼ")); @@ -419,6 +430,7 @@ void HPPA::createMoveplatformActionGroup() moveplatformActionGroup->addAction(ui.mAction_2AxisMotor); moveplatformActionGroup->addAction(ui.mAction_RobotArm); moveplatformActionGroup->addAction(ui.mAction_1AxisMotor); + moveplatformActionGroup->addAction(ui.mAction_2AxisMotor_new); // ȡϴѡĽ QSettings settings; @@ -441,6 +453,10 @@ void HPPA::createMoveplatformActionGroup() { ui.mAction_1AxisMotor->setChecked(true); } + else if (lastSelectedAction == "mAction_2AxisMotor_new") + { + ui.mAction_2AxisMotor_new->setChecked(true); + } } void HPPA::selectingMoveplatform(QAction* selectedAction) @@ -562,6 +578,7 @@ void HPPA::onStartRecordStep1() string directory = fileOperation->getDirectoryFromString(); //string imgPath = directory + "\\tmp_image"; string imgPath = directory + "\\" + m_FilenameLineEdit->text().toStdString(); + string x_location = removeFileExtension(imgPath) + "_x_location.pos"; m_RecordState += 1; if (m_RecordState % 2 == 1) @@ -599,7 +616,6 @@ void HPPA::onStartRecordStep1() ui.ImageViewerTabWidget->clear(); onCreateTab(0); - m_numberOfRecording = 0; m_Imager->setFileName2Save(imgPath); m_Imager->setFrameNumber(this->frame_number->text().toInt()); @@ -627,7 +643,6 @@ void HPPA::onStartRecordStep1() ui.ImageViewerTabWidget->clear(); onCreateTab(0); - m_numberOfRecording = 0; ui.action_start_recording->setText(QString::fromLocal8Bit("ֹͣɼ")); ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(255,0,0);}"); @@ -686,8 +701,6 @@ void HPPA::onStartRecordStep1() //ɾtab ui.ImageViewerTabWidget->clear(); - //¼xλõļ - string x_location = removeFileExtension(imgPath) + "x_location.pos"; m_hTimesFile = fopen(x_location.c_str(), "w+"); m_Imager->setFileName2Save(imgPath); @@ -721,6 +734,35 @@ void HPPA::onStartRecordStep1() return; } + else if (checkedName == "mAction_2AxisMotor_new") + { + m_RecordState += 1; + + if (m_RecordState % 2 == 1) + { + ui.ImageViewerTabWidget->clear(); + + m_Imager->setFileName2Save(imgPath); + m_Imager->setFrameNumber(this->frame_number->text().toInt()); + tmc->setImager(m_Imager); + tmc->setPosFileName(QString::fromStdString(x_location)); + tmc->run(); + + ui.action_start_recording->setText(QString::fromLocal8Bit("ֹͣɼ")); + ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(255,0,0);}"); + } + else + { + tmc->stop(); + + m_RecordState--; + + ui.action_start_recording->setText(QString::fromLocal8Bit("ɼ")); + ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(0,255,0);}"); + } + + return; + } else if (checkedName == "mAction_RobotArm") { //жǷѡִкRobotArmControl::executeTask޸ʾbug @@ -790,6 +832,8 @@ void HPPA::onCreateTab(int trackNumber) { if (trackNumber >= 0) { + m_numberOfRecording = trackNumber; + QWidget * tabTmp = new QWidget(); QGridLayout *GridLayout = new QGridLayout(); @@ -1755,6 +1799,13 @@ void HPPA::getRequest(QString str) void HPPA::newMotor() { + QAction* checked = moveplatformActionGroup->checkedAction(); + QString checkedName = checked->objectName(); + if (checkedName != "mAction_2AxisMotor") + { + return; + } + if (m_xMotor != nullptr && m_yMotor != nullptr) { return; @@ -1932,7 +1983,7 @@ void HPPA::onconnect() m_Imager->connect_imager(frame_number->text().toInt()); m_Imager->setFileName2Save(m_FilenameLineEdit->text().toStdString()); - connect(m_Imager, SIGNAL(PlotSignal(int)), this, SLOT(onPlotHyperspectralImageRgbImage(int))); + connect(m_Imager, SIGNAL(PlotSignal(int, int)), this, SLOT(onPlotHyperspectralImageRgbImage(int, int))); connect(m_Imager, SIGNAL(RecordFinishedSignal_WhenFrameNumberMeet()), this, SLOT(onRecordFinishedSignal_WhenFrameNumberMeet())); connect(m_Imager, SIGNAL(RecordFinishedSignal_WhenFrameNumberNotMeet()), this, SLOT(onRecordFinishedSignal_WhenFrameNumberNotMeet())); connect(m_Imager, SIGNAL(SpectralSignal(int)), this, SLOT(PlotSpectral(int))); @@ -2171,19 +2222,19 @@ void HPPA::recordWhiteFinish() } } -void HPPA::onPlotHyperspectralImageRgbImage(int number) +void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber) { //ʹûе۲ɼʱֹͣɼ˲ֿʼɼᵼϴβɼźŵô˲ۺ QAction* checked = moveplatformActionGroup->checkedAction(); QString checkedName = checked->objectName(); - if (number == -1 && checkedName == "mAction_RobotArm") + if (frameNumber == -1 && checkedName == "mAction_RobotArm") { return; } //return; //ȡͼؼ - QWidget* currentWidget = ui.ImageViewerTabWidget->widget(m_numberOfRecording); + QWidget* currentWidget = ui.ImageViewerTabWidget->widget(fileNumber); QList currentImageViewer = currentWidget->findChildren(); currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//ʾѾɼ֡ @@ -2333,6 +2384,10 @@ void HPPA::onRecordFinishedSignal_WhenFrameNumberNotMeet() return; } + if (checkedName == "mAction_2AxisMotor_new")//жɼߣмijɼɺ󲻴ɼ + { + return; + } std::cout << "ֹͣɼԭ򣺣1֡ûвɼʱﵽλã2ֶֹͣɼ" << std::endl; @@ -2342,6 +2397,14 @@ void HPPA::onRecordFinishedSignal_WhenFrameNumberNotMeet() m_RecordState++; } +void HPPA::onsequenceComplete() +{ + ui.action_start_recording->setText(QString::fromLocal8Bit("ɼ")); + ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(0,255,0);}"); + + m_RecordState++; +} + ForLoopControl::ForLoopControl() { diff --git a/HPPA/HPPA.h b/HPPA/HPPA.h index e9e7e53..b3e4dc1 100644 --- a/HPPA/HPPA.h +++ b/HPPA/HPPA.h @@ -35,6 +35,7 @@ #include "PathPlan.h" #include "RobotArmControl.h" #include "OneMotorControl.h" +#include "TwoMotorControl.h" #include "hppaConfigFile.h" #include "path_tc.h" @@ -248,6 +249,9 @@ private: OneMotorControl* omc; QDockWidget* dock_omc; + + TwoMotorControl* tmc; + QDockWidget* dock_tmc; PathPlan* m_pathPlan; @@ -255,10 +259,11 @@ private: FILE* m_hTimesFile; public Q_SLOTS: - void onPlotHyperspectralImageRgbImage(int number); + void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber); void PlotSpectral(int state); void onRecordFinishedSignal_WhenFrameNumberMeet(); void onRecordFinishedSignal_WhenFrameNumberNotMeet(); + void onsequenceComplete(); void onExit(); void onconnect();// diff --git a/HPPA/HPPA.ui b/HPPA/HPPA.ui index 7487b57..a1eb60f 100644 --- a/HPPA/HPPA.ui +++ b/HPPA/HPPA.ui @@ -88,6 +88,11 @@ 30 + + + -1 + + QMenuBar{ background:#F0F0F0; @@ -123,6 +128,10 @@ color:white; 文件 + + + + @@ -130,6 +139,11 @@ color:white; 光谱仪 + + + 宋体 + + 选择相机类型 @@ -169,11 +183,33 @@ color:white; + + + + 应用场景 + + + + + + + + + + + 数据处理 + + + + + + + @@ -185,6 +221,12 @@ color:white; 0 + + + 宋体 + 2 + + 相机控制 @@ -301,13 +343,6 @@ QGroupBox:title { 0 - - - - 打开 - - - @@ -315,6 +350,13 @@ QGroupBox:title { + + + + 打开 + + + @@ -1450,6 +1492,11 @@ QDockWidget::title { 退出 + + + Adobe Devanagari + + @@ -1493,6 +1540,11 @@ QDockWidget::title { 连接相机 + + + 宋体 + + @@ -1506,6 +1558,11 @@ QDockWidget::title { Pika L + + + 宋体 + + @@ -1522,6 +1579,11 @@ QDockWidget::title { Pika XC2 + + + 宋体 + + @@ -1535,6 +1597,11 @@ QDockWidget::title { Pika NIR + + + 宋体 + + @@ -1595,6 +1662,74 @@ QDockWidget::title { 1 轴线性马达 + + + 室内1轴线性平台 + + + + + 辐亮度 + + + + + 反射率 + + + + + 机械臂 + + + + + 显微镜 + + + + + 三脚架(旋转平台) + + + + + 打开影像 + + + + + 关闭影像 + + + + + 设置 + + + + + 拼接 + + + + + 植物表型 + + + + + 2轴旋转平台 + + + + + true + + + 2 轴线性马达_new + + diff --git a/HPPA/ImagerOperationBase.cpp b/HPPA/ImagerOperationBase.cpp index ff9ba72..2fd33f4 100644 --- a/HPPA/ImagerOperationBase.cpp +++ b/HPPA/ImagerOperationBase.cpp @@ -6,7 +6,7 @@ ImagerOperationBase::ImagerOperationBase() m_bRecordControlState = true; m_FileName2Save = "tmp_image"; - m_FileSavedCounter = 1; + m_FileSavedCounter = 0; m_RgbImage = new CImage(); @@ -299,7 +299,7 @@ void ImagerOperationBase::start_record() //ÿ1sһνͼλ if (m_iFrameCounter % (int)getFramerate() == 0) { - emit PlotSignal(m_iFrameCounter); + emit PlotSignal(m_FileSavedCounter, m_iFrameCounter); } if (m_iFrameCounter >= m_iFrameNumber) @@ -310,14 +310,14 @@ void ImagerOperationBase::start_record() } imagerStopCollect(); + //һλͼǰҪһ + //m_RgbImage + emit PlotSignal(m_FileSavedCounter, -1);//1ɼɺһλͼԷɼ֡֡ʵıʱͼȫ2ʹûе۲ɼʱֹͣɼ˲俪ʼɼᵼϴβɼĴźŵõIJۺΪ˼ݣע͵ + m_bRecordControlState = false; WriteHdr(); m_FileSavedCounter++; - //һλͼǰҪһ - //m_RgbImage - emit PlotSignal(-1);//1ɼɺһλͼԷɼ֡֡ʵıʱͼȫ2ʹûе۲ɼʱֹͣɼ˲俪ʼɼᵼϴβɼĴźŵõIJۺΪ˼ݣע͵ - if (m_iFrameCounter >= m_iFrameNumber) { emit RecordFinishedSignal_WhenFrameNumberMeet(); @@ -341,7 +341,7 @@ void ImagerOperationBase::setFrameNumber(int FrameNumber) void ImagerOperationBase::setFileName2Save(string FileName) { m_FileName2Save = FileName; - m_FileSavedCounter = 1; + m_FileSavedCounter = 0; } void ImagerOperationBase::setFocusControlState(bool FocusControlState) @@ -449,6 +449,11 @@ void ImagerOperationBase::setRecordControlState(bool RecordControlState) m_bRecordControlState = RecordControlState; } +void ImagerOperationBase::stop_record() +{ + m_bRecordControlState = false; +} + int ImagerOperationBase::getFrameCounter() const { return m_iFrameCounter; diff --git a/HPPA/ImagerOperationBase.h b/HPPA/ImagerOperationBase.h index 2e017d0..fdc3480 100644 --- a/HPPA/ImagerOperationBase.h +++ b/HPPA/ImagerOperationBase.h @@ -94,12 +94,13 @@ public slots: virtual double auto_exposure(); virtual void focus(); virtual void start_record(); + void stop_record(); virtual void record_dark(); virtual void record_white(); void getFocusIndexSobel(); signals: - void PlotSignal(int);//Ӱźţ-1˴βɼһλ + void PlotSignal(int, int);//ӰźţһڼӰ񣻵ڶɼ֡-1˴βɼһλ void RecordFinishedSignal_WhenFrameNumberMeet();//ɼźţҪɼ֡m_iFrameNumberɼ void RecordFinishedSignal_WhenFrameNumberNotMeet();//ɼźţҪɼ֡m_iFrameNumberûвɼɣ;ֹͣɼ void SpectralSignal(int);//1ڵƹף0ʾɣ diff --git a/HPPA/ResononNirImager.cpp b/HPPA/ResononNirImager.cpp index 646ced1..6d1f92c 100644 --- a/HPPA/ResononNirImager.cpp +++ b/HPPA/ResononNirImager.cpp @@ -353,7 +353,7 @@ void ResononNirImager::start_record() //ÿ1sһνͼλ if (m_iFrameCounter % (int)getFramerate() == 0) { - emit PlotSignal(m_iFrameCounter); + emit PlotSignal(m_FileSavedCounter, m_iFrameCounter); } if (m_iFrameCounter >= m_iFrameNumber) @@ -365,14 +365,14 @@ void ResononNirImager::start_record() } imagerStopCollect(); + //һλͼǰҪһ + //m_RgbImage + emit PlotSignal(m_FileSavedCounter, -1);//ɼɺһλͼԷɼ֡֡ʵıʱͼȫ + m_bRecordControlState = false; WriteHdr(); m_FileSavedCounter++; - //һλͼǰҪһ - //m_RgbImage - emit PlotSignal(-1);//ɼɺһλͼԷɼ֡֡ʵıʱͼȫ - if (m_iFrameCounter >= m_iFrameNumber) { emit RecordFinishedSignal_WhenFrameNumberMeet(); diff --git a/HPPA/TwoMotorControl.cpp b/HPPA/TwoMotorControl.cpp new file mode 100644 index 0000000..ecec9b5 --- /dev/null +++ b/HPPA/TwoMotorControl.cpp @@ -0,0 +1,581 @@ +#include "TwoMotorControl.h" + +TwoMotorControl::TwoMotorControl(QWidget* parent) : QDialog(parent) +{ + ui.setupUi(this); + + ui.recordLine_tableWidget->setFocusPolicy(Qt::NoFocus); + ui.recordLine_tableWidget->setStyleSheet("selection-background-color:rgb(255,209,128)");//设置选择的行高亮 + + ui.recordLine_tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选择行为,以行为单位 + //ui.recordLine_tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);//设置选择模式,选择单行 + //QHeaderView* headerView = ui.recordLine_tableWidget->verticalHeader(); + //headerView->setHidden(true);//去除左边默认自带序列号 + + connect(this->ui.connect_btn, SIGNAL(pressed()), this, SLOT(onConnectMotor())); + + connect(ui.addRecordLine_btn, SIGNAL(clicked()), this, SLOT(onAddRecordLine_btn())); + connect(ui.removeRecordLine_btn, SIGNAL(clicked()), this, SLOT(onRemoveRecordLine_btn())); + connect(ui.generateRecordLine_btn, SIGNAL(clicked()), this, SLOT(onGenerateRecordLine_btn())); + connect(ui.deleteRecordLine_btn, SIGNAL(clicked()), this, SLOT(onDeleteRecordLine_btn())); + connect(ui.saveRecordLine2File_btn, SIGNAL(clicked()), this, SLOT(onSaveRecordLine2File_btn())); + connect(ui.readRecordLineFile_btn, SIGNAL(clicked()), this, SLOT(onReadRecordLineFile_btn())); + + connect(ui.run_btn, SIGNAL(clicked()), this, SLOT(run())); + connect(ui.stop_btn, SIGNAL(clicked()), this, SLOT(stop())); +} + +void TwoMotorControl::setImager(ImagerOperationBase* imager) +{ + m_Imager = imager; +} + +void TwoMotorControl::setPosFileName(QString posFileName) +{ + isWritePosFile = true; + m_posFileName = posFileName; + m_posFileHandle = fopen(posFileName.toStdString().c_str(), "w+"); +} + +bool TwoMotorControl::getState() +{ + QEventLoop loop; + bool tmp = false; + bool received = false; + + QTimer timer; + timer.setSingleShot(true); + connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + + QMetaObject::Connection conn = QObject::connect( + m_coordinator, &TwoMotionCaptureCoordinator::recordState, + [&](bool state) { + tmp = state; + received = true; + loop.quit(); + }); + + QMetaObject::invokeMethod(m_coordinator, "getRecordState", Qt::QueuedConnection); + timer.start(3000); + + loop.exec(); + + disconnect(conn); + + return tmp; +} + +void TwoMotorControl::run() +{ + if (m_coordinator==nullptr) + { + qRegisterMetaType>("QVector"); + m_coordinator = new TwoMotionCaptureCoordinator(m_multiAxisController, m_Imager); + m_coordinator->moveToThread(&m_coordinatorThread); + connect(&m_coordinatorThread, SIGNAL(finished()), m_coordinator, SLOT(deleteLater())); + connect(this, SIGNAL(start(QVector)), m_coordinator, SLOT(start(QVector))); + connect(this, SIGNAL(stopSignal()), m_coordinator, SLOT(stop())); + connect(m_coordinator, SIGNAL(startRecordLineNumSignal(int)), this, SLOT(receiveStartRecordLineNum(int))); + connect(m_coordinator, SIGNAL(finishRecordLineNumSignal(int)), this, SLOT(receiveFinishRecordLineNum(int))); + connect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete())); + m_coordinatorThread.start(); + } + + if (getState()) + { + //std::cout << "已经开始运行,请勿重复点击!!!!!!!!" << std::endl; + QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("已经开始运行,请勿重复点击!!!!!!!!!")); + return; + } + + QVector pathLines; + int rowCount = ui.recordLine_tableWidget->rowCount(); + //int columnCount = ui.recordLine_tableWidget->columnCount(); + for (size_t i = 0; i < rowCount; i++) + { + PathLine tmp; + + tmp.targetYPosition = ui.recordLine_tableWidget->item(i, 0)->text().toDouble(); + tmp.speedTargetYPosition = ui.recordLine_tableWidget->item(i, 1)->text().toDouble(); + tmp.targetXMinPosition = ui.recordLine_tableWidget->item(i, 2)->text().toDouble(); + tmp.speedTargetXMinPosition = ui.recordLine_tableWidget->item(i, 3)->text().toDouble(); + tmp.targetXMaxPosition = ui.recordLine_tableWidget->item(i, 4)->text().toDouble(); + tmp.speedTargetXMaxPosition = ui.recordLine_tableWidget->item(i, 5)->text().toDouble(); + + pathLines.append(tmp); + } + + for (size_t i = 0; i < ui.recordLine_tableWidget->rowCount(); i++) + { + for (size_t j = 0; j < ui.recordLine_tableWidget->columnCount(); j++) + { + ui.recordLine_tableWidget->item(i, j)->setBackgroundColor(QColor(240, 240, 240)); + } + } + + emit start(pathLines); +} + +void TwoMotorControl::stop() +{ + emit stopSignal(); +} + +TwoMotorControl::~TwoMotorControl() +{ + m_motorThread.quit(); + m_motorThread.wait(); + + m_coordinatorThread.quit(); + m_coordinatorThread.wait(); +} + +void TwoMotorControl::onConnectMotor() +{ + try + { + FileOperation* fileOperation = new FileOperation(); + string directory = fileOperation->getDirectoryOfExe(); + QString configFilePath = QString::fromStdString(directory) + "\\twoMotorConfigFile.cfg"; + + m_multiAxisController = new IrisMultiMotorController(configFilePath); + } + catch (std::exception const& e) + { + QMessageBox msgBox; + msgBox.setText(QString::fromLocal8Bit("请连接马达!")); + msgBox.exec(); + } + + m_multiAxisController->moveToThread(&m_motorThread); + connect(&m_motorThread, SIGNAL(finished()), m_multiAxisController, SLOT(deleteLater())); + + connect(this->ui.xmotor_right_btn, SIGNAL(pressed()), this, SLOT(onxMotorRight())); + connect(this->ui.xmotor_right_btn, SIGNAL(released()), this, SLOT(onxMotorStop())); + connect(this->ui.xmotor_left_btn, SIGNAL(pressed()), this, SLOT(onxMotorLeft())); + connect(this->ui.xmotor_left_btn, SIGNAL(released()), this, SLOT(onxMotorStop())); + + connect(this->ui.ymotor_forward_btn, SIGNAL(pressed()), this, SLOT(onyMotorforward())); + connect(this->ui.ymotor_forward_btn, SIGNAL(released()), this, SLOT(onyMotorStop())); + connect(this->ui.ymotor_backward_btn, SIGNAL(pressed()), this, SLOT(onyMotorbackward())); + connect(this->ui.ymotor_backward_btn, SIGNAL(released()), this, SLOT(onyMotorStop())); + + //connect(this->ui.move2loc_pushButton, SIGNAL(pressed()), this, SLOT(onxMove2Loc())); + + connect(m_multiAxisController, SIGNAL(broadcastLocationSignal(std::vector)), this, SLOT(displayRealTimeLoc(std::vector))); + + connect(this, SIGNAL(moveSignal(int, bool, double, int)), m_multiAxisController, SLOT(move(int, bool, double, int))); + //connect(this, SIGNAL(move2LocSignal(int, double, double, int)), m_multiAxisController, SLOT(moveTo(int, double, double, int))); + connect(this, SIGNAL(stopSignal(int)), m_multiAxisController, SLOT(stop(int))); + + connect(this->ui.zero_start_btn, SIGNAL(released()), this, SLOT(zeroStart())); + connect(this, SIGNAL(zeroStartSignal(int)), m_multiAxisController, SLOT(zeroStart(int))); + + connect(this->ui.rangeMeasurement_btn, SIGNAL(pressed()), this, SLOT(on_rangeMeasurement())); + connect(this, SIGNAL(rangeMeasurement(int, double, int)), m_multiAxisController, SLOT(rangeMeasurement(int, double, int))); + + connect(this, SIGNAL(testConnectivitySignal(int, int)), m_multiAxisController, SLOT(testConnectivity(int, int))); + connect(m_multiAxisController, SIGNAL(broadcastConnectivity(std::vector)), this, SLOT(display_motors_connectivity(std::vector))); + + m_motorThread.start(); + emit testConnectivitySignal(0, 1000); + emit testConnectivitySignal(1, 1000); +} + +void TwoMotorControl::receiveStartRecordLineNum(int lineNum) +{ + emit startLineNumSignal(lineNum); + for (size_t i = 0; i < ui.recordLine_tableWidget->columnCount(); i++) + { + ui.recordLine_tableWidget->item(lineNum, i)->setBackgroundColor(QColor(255, 0, 0)); + } +} + +void TwoMotorControl::receiveFinishRecordLineNum(int lineNum) +{ + for (size_t i = 0; i < ui.recordLine_tableWidget->columnCount(); i++) + { + ui.recordLine_tableWidget->item(lineNum, i)->setBackgroundColor(QColor(0, 255, 0)); + } +} + +void TwoMotorControl::onSequenceComplete() +{ + isWritePosFile = false; + fclose(m_posFileHandle); + + emit sequenceComplete(); +} + +void TwoMotorControl::display_motors_connectivity(std::vector connectivity) +{ + //std::cout << "-----------------------------------"<ui.xMotorStateLabel->setStyleSheet("QLabel{background-color:rgb(0,255,0);}"); + } + else + { + this->ui.xMotorStateLabel->setStyleSheet("QLabel{background-color:rgb(255,0,0);}"); + } + + if (connectivity[1]) + { + this->ui.yMotorStateLabel->setStyleSheet("QLabel{background-color:rgb(0,255,0);}"); + } + else + { + this->ui.yMotorStateLabel->setStyleSheet("QLabel{background-color:rgb(255,0,0);}"); + } +} + +void TwoMotorControl::onxMotorRight() +{ + double s = ui.xmotor_move_speed_lineEdit->text().toDouble(); + + emit moveSignal(0, false, s, 1000); +} + +void TwoMotorControl::onxMotorLeft() +{ + double s = ui.xmotor_move_speed_lineEdit->text().toDouble(); + + emit moveSignal(0, true, s, 1000); +} + +void TwoMotorControl::onxMotorStop() +{ + emit stopSignal(0); +} + +void TwoMotorControl::onyMotorforward() +{ + double s = ui.ymotor_move_speed_lineEdit->text().toDouble(); + + emit moveSignal(1, false, s, 1000); +} + +void TwoMotorControl::onyMotorbackward() +{ + double s = ui.ymotor_move_speed_lineEdit->text().toDouble(); + + emit moveSignal(1, true, s, 1000); +} + +void TwoMotorControl::onyMotorStop() +{ + emit stopSignal(1); +} + +void TwoMotorControl::displayRealTimeLoc(std::vector loc) +{ + double tmp = round(loc[0] * 100) / 100; + if (isWritePosFile) + { + long long timeOs = getNanosecondsSinceMidnight(); + fprintf(m_posFileHandle, "%lld,%f\n", timeOs, loc[0]); + } + this->ui.xmotor_realTimeLoc_lineEdit->setText(QString::number(tmp)); + + tmp = round(loc[1] * 100) / 100; + this->ui.ymotor_realTimeLoc_lineEdit->setText(QString::number(tmp)); +} + +void TwoMotorControl::zeroStart() +{ + zeroStartSignal(0); + zeroStartSignal(1); +} + +void TwoMotorControl::on_rangeMeasurement() +{ + double s0 = ui.xmotor_move_speed_lineEdit->text().toDouble(); + emit rangeMeasurement(0, s0, 1000); + + s0 = ui.ymotor_move_speed_lineEdit->text().toDouble(); + emit rangeMeasurement(1, s0, 1000); +} + +void TwoMotorControl::onAddRecordLine_btn() +{ + //准备数据:获取y马达的当前位置,获取x马达的当前位置和最大位置 + double currentPosOfYmotor = 15; + + double currentPosOfXmotor = 0; + double maxRangeOfXmotor = 50; + + //获取选中行的索引 + int currentRow = ui.recordLine_tableWidget->currentRow(); + std::cout << "currentRow:" << currentRow << std::endl; + + QTableWidgetItem* Item1 = new QTableWidgetItem(QString::number(currentPosOfYmotor, 10, 2)); + QTableWidgetItem* Item2 = new QTableWidgetItem(QString::number(1, 10, 2)); + QTableWidgetItem* Item3 = new QTableWidgetItem(QString::number(currentPosOfXmotor, 10, 2)); + QTableWidgetItem* Item4 = new QTableWidgetItem(QString::number(1, 10, 2)); + QTableWidgetItem* Item5 = new QTableWidgetItem(QString::number(maxRangeOfXmotor, 10, 2)); + QTableWidgetItem* Item6 = new QTableWidgetItem(QString::number(1, 10, 2)); + Item1->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + Item2->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + Item3->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + Item4->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + Item5->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + Item6->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + if (currentRow == -1)//当没有选中行时 + { + int RowCount = ui.recordLine_tableWidget->rowCount();//Returns the number of rows. 从1开始的 + ui.recordLine_tableWidget->insertRow(RowCount);//增加一行,形参是从0开始的 + + ui.recordLine_tableWidget->setItem(RowCount, 0, Item1); + ui.recordLine_tableWidget->setItem(RowCount, 1, Item2); + ui.recordLine_tableWidget->setItem(RowCount, 2, Item3); + ui.recordLine_tableWidget->setItem(RowCount, 3, Item4); + ui.recordLine_tableWidget->setItem(RowCount, 4, Item5); + ui.recordLine_tableWidget->setItem(RowCount, 5, Item6); + } + else + { + ui.recordLine_tableWidget->insertRow(currentRow + 1);//增加一行,形参是从0开始的 + + ui.recordLine_tableWidget->setItem(currentRow + 1, 0, Item1); + ui.recordLine_tableWidget->setItem(currentRow + 1, 1, Item2); + ui.recordLine_tableWidget->setItem(currentRow + 1, 2, Item3); + ui.recordLine_tableWidget->setItem(currentRow + 1, 3, Item4); + ui.recordLine_tableWidget->setItem(currentRow + 1, 4, Item5); + ui.recordLine_tableWidget->setItem(currentRow + 1, 5, Item6); + } +} + +void TwoMotorControl::onRemoveRecordLine_btn() +{ + int rowIndex = ui.recordLine_tableWidget->currentRow(); + if (rowIndex != -1) + ui.recordLine_tableWidget->removeRow(rowIndex); +} + +void TwoMotorControl::onGenerateRecordLine_btn() +{ + //求幅宽 + double height = ui.height_lineEdit->text().toDouble(); + double fov = ui.fov_lineEdit->text().toDouble(); + double swath = (height * tan(fov / 2 * PI / 180)) * 2;//tan输入是弧度 + ui.swath_lineEdit->setText(QString::number(swath)); + + + //读取马达测量范围 + double xMotorRange = 50; + double yMotorRange = 500; + + + //确定有多少条采集线,公式:numberOfRecordLine_tmp * swath - repetitiveLength(numberOfRecordLine_tmp - 1) = overallLength + double overallLength = yMotorRange + swath; + double repetitiveRate = ui.repetitiveRate_lineEdit->text().toDouble() / 100; + double repetitiveLength = repetitiveRate * swath; + double offset = ui.offset_lineEdit->text().toDouble(); + + double numberOfRecordLine_tmp = (overallLength - repetitiveLength - offset) / (swath - repetitiveLength); + double tmp = numberOfRecordLine_tmp - (int)numberOfRecordLine_tmp; + int numberOfRecordLine; + double threshold = ui.LastLineThreshold_lineEdit->text().toDouble();//当numberOfRecordLine_tmp为小数时,判断是否多加一条采集线 + if (tmp > threshold) + { + numberOfRecordLine = (int)numberOfRecordLine_tmp + 1; + //std::cout << "大于:" << threshold << std::endl; + } + else + { + numberOfRecordLine = (int)numberOfRecordLine_tmp; + } + + + + //去掉tableWidget中所有的行 + int rowCount = ui.recordLine_tableWidget->rowCount(); + for (size_t i = 0; i < rowCount; i++) + { + ui.recordLine_tableWidget->removeRow(0); + } + + + //向tableWidget添加行(采集线) + QTableWidgetItem* tmpItem; + for (size_t i = 0; i < numberOfRecordLine; i++) + { + //增加一行 + int RowCount = ui.recordLine_tableWidget->rowCount(); + ui.recordLine_tableWidget->insertRow(RowCount); + + //设置yPosition + if (tmp > threshold && i == numberOfRecordLine - 1)//设置最后一行的yPosition + { + tmpItem = new QTableWidgetItem(QString::number(yMotorRange, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 0, tmpItem); + } + else + { + double x = swath * i - i * repetitiveLength + offset; + tmpItem = new QTableWidgetItem(QString::number(x, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 0, tmpItem); + } + tmpItem = new QTableWidgetItem(QString::number(1, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 1, tmpItem); + + tmpItem = new QTableWidgetItem(QString::number(0, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 2, tmpItem); + tmpItem = new QTableWidgetItem(QString::number(1, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 3, tmpItem); + + //设置x马达最大运动位置 → 值设置为x马达量程 + tmpItem = new QTableWidgetItem(QString::number(xMotorRange, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 4, tmpItem); + tmpItem = new QTableWidgetItem(QString::number(1, 10, 2)); + tmpItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, 5, tmpItem); + } +} + +void TwoMotorControl::onDeleteRecordLine_btn() +{ + int rowCount = ui.recordLine_tableWidget->rowCount(); + for (size_t i = 0; i < rowCount; i++) + { + ui.recordLine_tableWidget->removeRow(0); + } +} + +void TwoMotorControl::onSaveRecordLine2File_btn() +{ + //确保采集线存在 + if (ui.recordLine_tableWidget->rowCount() <= 0) + { + QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("请先生成轨迹!")); + return; + } + + double height = ui.height_lineEdit->text().toDouble(); + double fov = ui.fov_lineEdit->text().toDouble(); + double swath = ui.swath_lineEdit->text().toDouble(); + double offset = ui.offset_lineEdit->text().toDouble(); + double repetitiveRate = ui.repetitiveRate_lineEdit->text().toDouble(); + double LastLineThreshold = ui.LastLineThreshold_lineEdit->text().toDouble(); + + FileOperation* fileOperation = new FileOperation(); + string directory = fileOperation->getDirectoryOfExe(); + + QString RecordLineFilePath = QFileDialog::getSaveFileName(this, tr("Save RecordLine2 File"), + QString::fromStdString(directory), + tr("RecordLineFile2 (*.RecordLine2)")); + + if (RecordLineFilePath.isEmpty()) + { + return; + } + + FILE* RecordLineFileHandle = fopen(RecordLineFilePath.toStdString().c_str(), "wb+"); + + fwrite(&height, sizeof(double), 1, RecordLineFileHandle); + fwrite(&fov, sizeof(double), 1, RecordLineFileHandle); + fwrite(&swath, sizeof(double), 1, RecordLineFileHandle); + fwrite(&offset, sizeof(double), 1, RecordLineFileHandle); + fwrite(&repetitiveRate, sizeof(double), 1, RecordLineFileHandle); + fwrite(&LastLineThreshold, sizeof(double), 1, RecordLineFileHandle); + + double number = ui.recordLine_tableWidget->rowCount() * ui.recordLine_tableWidget->columnCount(); + fwrite(&number, sizeof(double), 1, RecordLineFileHandle); + + double* data = new double[number]; + //double data[number]; + for (size_t i = 0; i < ui.recordLine_tableWidget->rowCount(); i++) + { + for (size_t j = 0; j < ui.recordLine_tableWidget->columnCount(); j++) + { + data[i * ui.recordLine_tableWidget->columnCount() + j] = ui.recordLine_tableWidget->item(i, j)->text().toDouble(); + } + } + + fwrite(data, sizeof(double), number, RecordLineFileHandle); + + fclose(RecordLineFileHandle); + delete[] data; + + QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("保存成功!")); +} + +void TwoMotorControl::onReadRecordLineFile_btn() +{ + //打开文件 + FileOperation* fileOperation = new FileOperation(); + string directory = fileOperation->getDirectoryOfExe(); + + QString RecordLineFilePath = QFileDialog::getOpenFileName(this, tr("Open RecordLine2 File"), + QString::fromStdString(directory), + tr("RecordLineFile (*.RecordLine2)")); + + if (RecordLineFilePath.isEmpty()) + { + return; + } + + FILE* RecordLineFileHandle = fopen(RecordLineFilePath.toStdString().c_str(), "rb"); + double height, fov, swath, offset, repetitiveRate, LastLineThreshold, number; + + //读取数据 + fread(&height, sizeof(double), 1, RecordLineFileHandle); + fread(&fov, sizeof(double), 1, RecordLineFileHandle); + fread(&swath, sizeof(double), 1, RecordLineFileHandle); + fread(&offset, sizeof(double), 1, RecordLineFileHandle); + fread(&repetitiveRate, sizeof(double), 1, RecordLineFileHandle); + fread(&LastLineThreshold, sizeof(double), 1, RecordLineFileHandle); + fread(&number, sizeof(double), 1, RecordLineFileHandle); + + double* data = new double[number]; + for (size_t i = 0; i < number; i++) + { + fread(data + i, sizeof(double), 1, RecordLineFileHandle); + //std::cout << *(data + i) << std::endl; + } + + //向界面中填写 + ui.height_lineEdit->setText(QString::number(height)); + ui.fov_lineEdit->setText(QString::number(fov)); + ui.swath_lineEdit->setText(QString::number(swath)); + ui.offset_lineEdit->setText(QString::number(offset)); + ui.repetitiveRate_lineEdit->setText(QString::number(repetitiveRate)); + ui.LastLineThreshold_lineEdit->setText(QString::number(LastLineThreshold)); + + + //向tableWidget添加采集线 + //(1)去掉tableWidget中所有的行 + int rowCount = ui.recordLine_tableWidget->rowCount(); + for (size_t i = 0; i < rowCount; i++) + { + ui.recordLine_tableWidget->removeRow(0); + } + //(2)添加行(采集线) + int RecordLineCount = number / ui.recordLine_tableWidget->columnCount(); + for (size_t i = 0; i < RecordLineCount; i++) + { + ui.recordLine_tableWidget->insertRow(0); + + } + //(3)向tableWidget填充数据 + for (size_t i = 0; i < ui.recordLine_tableWidget->rowCount(); i++) + { + for (size_t j = 0; j < ui.recordLine_tableWidget->columnCount(); j++) + { + QTableWidgetItem* tmp = new QTableWidgetItem(QString::number(data[i * ui.recordLine_tableWidget->columnCount() + j], 10, 5)); + tmp->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + ui.recordLine_tableWidget->setItem(i, j, tmp); + } + } + + fclose(RecordLineFileHandle); + delete[] data; + + QMessageBox::information(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("读取成功!")); +} diff --git a/HPPA/TwoMotorControl.h b/HPPA/TwoMotorControl.h new file mode 100644 index 0000000..f9d7627 --- /dev/null +++ b/HPPA/TwoMotorControl.h @@ -0,0 +1,89 @@ +#pragma once +#include +#include +#include + +#include "ui_twoMotorControl.h" + +#include "IrisMultiMotorController.h" +#include "fileOperation.h" +#include "CaptureCoordinator.h" + +#define PI 3.1415926 + + + +class TwoMotorControl : public QDialog +{ + Q_OBJECT + +public: + TwoMotorControl(QWidget* parent = nullptr); + ~TwoMotorControl(); + + void setImager(ImagerOperationBase* imager); + void setPosFileName(QString posFileName); + +private: + ImagerOperationBase* m_Imager; + bool getState(); + + bool isWritePosFile = false; + QString m_posFileName; + FILE* m_posFileHandle; + + +public Q_SLOTS: + void onConnectMotor(); + + void displayRealTimeLoc(std::vector loc); + void display_motors_connectivity(std::vector connectivity); + //void onxMove2Loc(); + void zeroStart(); + void on_rangeMeasurement(); + + void onxMotorRight(); + void onxMotorLeft(); + void onxMotorStop(); + + void onyMotorforward(); + void onyMotorbackward(); + void onyMotorStop(); + + void onAddRecordLine_btn(); + void onRemoveRecordLine_btn(); + void onGenerateRecordLine_btn(); + void onDeleteRecordLine_btn(); + void onSaveRecordLine2File_btn(); + void onReadRecordLineFile_btn(); + + void run(); + void stop(); + void receiveStartRecordLineNum(int lineNum); + void receiveFinishRecordLineNum(int lineNum); + void onSequenceComplete(); + +signals: + void moveSignal(int, bool, double, int); + void move2LocSignal(int, double, double, int); + void move2LocSignal(const std::vector, const std::vector, int); + void stopSignal(int); + + void rangeMeasurement(int, double, int); + void zeroStartSignal(int); + void testConnectivitySignal(int, int); + + void start(QVector); + void stopSignal(); + + void startLineNumSignal(int lineNum); + void sequenceComplete();//所有采集线正常运行完成 + +private: + Ui::twoMotorControl_UI ui; + QThread m_coordinatorThread; + TwoMotionCaptureCoordinator* m_coordinator = nullptr; + + QThread m_motorThread; + IrisMultiMotorController* m_multiAxisController; +}; diff --git a/HPPA/twoMotorControl.ui b/HPPA/twoMotorControl.ui new file mode 100644 index 0000000..bdf59a0 --- /dev/null +++ b/HPPA/twoMotorControl.ui @@ -0,0 +1,1010 @@ + + + twoMotorControl_UI + + + + 0 + 0 + 684 + 674 + + + + 2轴马达控制 + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 684 + 674 + + + + + + + + 0 + 0 + + + + + + + 控制 + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + 运行 + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + 0 + 0 + + + + 连接 + + + + + + + + 0 + 0 + + + + ←0 + + + + + + + Qt::Horizontal + + + + 66 + 20 + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + 归零 + + + + + + + Qt::Horizontal + + + + 84 + 19 + + + + + + + + + 0 + 0 + + + + ↓0 + + + + + + + Qt::Horizontal + + + + 84 + 19 + + + + + + + + + 0 + 0 + + + + 量程检测 + + + + + + + + + + 停止 + + + + + + + + + + + 0 + 0 + + + + #QGroupBox{border:none} + + + x马达 + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + + 16777215 + 16777215 + + + + 运动速度 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + background-color: rgb(255, 255, 255); + + + 1 + + + Qt::AlignCenter + + + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + + 16777215 + 16777215 + + + + 实时位置 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + background-color: rgb(255, 255, 255); + + + 0 + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 112 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 50 + 0 + + + + 状态 + + + Qt::AlignCenter + + + + + + + + + + + + + 0 + 0 + + + + + + + y马达 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 运动速度 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + background-color: rgb(255, 255, 255); + + + 1 + + + Qt::AlignCenter + + + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + 实时位置 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + background-color: rgb(255, 255, 255); + + + 0 + + + Qt::AlignCenter + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 50 + 0 + + + + 状态 + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + 采集线 + + + + + + + + + 0 + 0 + + + + + 108 + 0 + + + + 高度 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + 100 + + + Qt::AlignCenter + + + + + + + Qt::LeftToRight + + + 生成轨迹 + + + + + + + 保存轨迹 + + + + + + + + + + + + 0 + 0 + + + + + 108 + 0 + + + + 视场角 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + 17.6 + + + Qt::AlignCenter + + + + + + + 删除轨迹 + + + + + + + 读取轨迹 + + + + + + + + + + + + 0 + 0 + + + + + 108 + 0 + + + + 偏移 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + 0 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + 幅宽 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 90 + 0 + + + + 0 + + + Qt::AlignCenter + + + true + + + + + + + 添加 + + + + + + + + + + + + 0 + 0 + + + + + 108 + 0 + + + + 重复率(%) + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + 0 + + + Qt::AlignCenter + + + false + + + + + + + 阈值 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 90 + 0 + + + + 0.7 + + + Qt::AlignCenter + + + false + + + + + + + 移除 + + + + + + + + + 6 + + + + yPosition + + + + + speed + + + + + xMinPosition + + + + + speed + + + + + xMaxPosition + + + + + speed + + + + + + + + + + + + + + + +