diff --git a/HPPA/CaptureCoordinator.cpp b/HPPA/CaptureCoordinator.cpp index 6d4b4b6..51f260d 100644 --- a/HPPA/CaptureCoordinator.cpp +++ b/HPPA/CaptureCoordinator.cpp @@ -972,3 +972,241 @@ double OneMotionCoordinator::getErrorRate(double targetLoc, double actualLoc) return errorRate; } + + + + + + + + + + + + + + + + + + + + + + + + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +OneMotorMultiPosCoordinator::OneMotorMultiPosCoordinator( + IrisMultiMotorController* motorCtrl, + ImagerOperationBase* cameraCtrl, + QObject* parent) + : QObject(parent) + , m_motorCtrl(motorCtrl) + , m_cameraCtrl(cameraCtrl) + , m_currentPos(0) + , m_isRunning(false) + , m_isZeroing(false) +{ + //这些信号槽是按照逻辑顺序的 + connect(this, SIGNAL(moveTo(int, double, double, int)), + m_motorCtrl, SLOT(moveTo(int, double, double, int))); + + connect(this, &OneMotorMultiPosCoordinator::zeroStart, + m_motorCtrl, &IrisMultiMotorController::zeroStart); + + connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, + this, &OneMotorMultiPosCoordinator::handlePositionReached); + //connect(m_motorCtrl, &IrisMultiMotorController::moveFailed, + // this, &OneMotorMultiPosCoordinator::handleError); + + connect(this, &OneMotorMultiPosCoordinator::getFocusIndexSobel, + m_cameraCtrl, &ImagerOperationBase::auto_exposure); + + connect(m_cameraCtrl, &ImagerOperationBase::autoExposureSignal, + this, &OneMotorMultiPosCoordinator::handleCaptureComplete); + //connect(m_cameraCtrl, &ImagerOperationBase::captureFailed, + // this, &OneMotorMultiPosCoordinator::handleError); +} + +OneMotorMultiPosCoordinator::~OneMotorMultiPosCoordinator() +{ + +} + +void OneMotorMultiPosCoordinator::startStepMotion(double speed, std::vector locations) +{ + QMutexLocker locker(&m_dataMutex); + + if (locations.empty()) + { + emit sequenceComplete(1); + + return; + } + + + if (m_isRunning) + { + emit errorOccurred("Sequence already running"); + return; + } + m_locations = locations; + + m_counter = 0; + + m_positionData.clear(); + + m_speed = speed; + m_iStepIntervalRealTime = 1; + + m_isRunning = true; + m_isZeroing = true; + + // 先执行归零操作 + emit zeroStart(0); + qDebug() << "OneMotorMultiPosCoordinator::startStepMotion: Zeroing started."; +} + +void OneMotorMultiPosCoordinator::startMotionSequence() +{ + QMutexLocker locker(&m_dataMutex); + + m_isZeroing = false; + qDebug() << "OneMotorMultiPosCoordinator::startMotionSequence: Zeroing complete. Starting motion sequence."; + + processNextPosition(); +} + +void OneMotorMultiPosCoordinator::handleZeroComplete(int motorID, double pos) +{ + if (!m_isRunning || !m_isZeroing) return; + + // 归零完成,开始分步运动 + startMotionSequence(); +} + +void OneMotorMultiPosCoordinator::stopStepMotion() +{ + QMutexLocker locker(&m_dataMutex); + m_isRunning = false; + emit sequenceStopped(); +} + +QVector OneMotorMultiPosCoordinator::getAllPositionData() const +{ + //QMutexLocker locker(&m_dataMutex); + return m_positionData; +} + +bool OneMotorMultiPosCoordinator::saveToCsv(const QString& filename) +{ + //QMutexLocker locker(&m_dataMutex); + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + return false; + } + + QTextStream out(&file); + out << "Timestamp,targetPosition,ActualPosition,exposureTime\n"; + + for (const auto& data : m_positionData) + { + out << data.timestamp.toString("yyyy-MM-dd HH:mm:ss.zzz") << "," + << QString::number(data.targetPosition, 'f', 4) << "," + << QString::number(data.actualPosition, 'f', 4) << "," + << QString::number(data.exposureTime, 'f', 4) << "\n"; + } + + file.close(); + return true; +} + +void OneMotorMultiPosCoordinator::handlePositionReached(int motorID, double pos) +{ + if (!m_isRunning) return; + + // 如果正在等待归零完成,调用归零完成处理 + if (m_isZeroing) + { + handleZeroComplete(motorID, pos); + return; + } + + QMutexLocker locker(&m_dataMutex); + + //验证马达运动位置是否到达指定位置 + //if (pos != m_currentPos) return; + + // 记录位置信息 + PositionsLogData data; + data.targetPosition = m_currentPos; + data.actualPosition = pos; + data.timestamp = QDateTime::currentDateTime(); + m_positionData.append(data); + + // 开始采集 + emit getFocusIndexSobel(); +} + +void OneMotorMultiPosCoordinator::handleCaptureComplete(double index) +{ + if (!m_isRunning) return; + + QMutexLocker locker(&m_dataMutex); + + // 更新最近一条记录的相机指数 + //if (!m_positionData.isEmpty() && + // m_positionData.last().targetPosition == m_positionData.last().actualPosition) + //{ + // m_positionData.last().cameraIndex = index; + //} + m_positionData.last().exposureTime = index; + + std::cout << "第" << m_counter << "次曝光:" << std::endl; + std::cout << "目标位置:" << m_positionData.last().targetPosition << std::endl; + std::cout << "实际位置:" << m_positionData.last().actualPosition << std::endl; + std::cout << "曝光时间:" << m_positionData.last().exposureTime << std::endl; + + processNextPosition(); +} + +void OneMotorMultiPosCoordinator::handleError(const QString& error) +{ + QMutexLocker locker(&m_dataMutex); + m_isRunning = false; + emit errorOccurred(error); +} + +void OneMotorMultiPosCoordinator::processNextPosition() +{ + if (!m_isRunning) return; + + if (m_locations.empty()) + { + m_isRunning = false; + emit sequenceComplete(0); + + // 计算平均曝光时间 + double avgExposureTime = 0.0; + for (const auto& data : m_positionData) { + avgExposureTime += data.exposureTime; + } + if (!m_positionData.isEmpty()) { + avgExposureTime /= m_positionData.size(); + } + + emit hyperAutoExposureDoneSignal(avgExposureTime); + m_cameraCtrl->setIntegrationTime(avgExposureTime); + + return; + } + + m_currentPos = m_locations.front(); + m_locations.erase(m_locations.begin()); + + emit moveTo(0, m_currentPos, m_speed, 1000); +} diff --git a/HPPA/CaptureCoordinator.h b/HPPA/CaptureCoordinator.h index ebadd83..5ac5d85 100644 --- a/HPPA/CaptureCoordinator.h +++ b/HPPA/CaptureCoordinator.h @@ -300,3 +300,74 @@ private: int m_retryTimes; bool m_reached; }; + + + +// 数据记录结构体 +struct PositionsLogData +{ + double targetPosition; // 目标位置 + double actualPosition; // 实际马达位置 + double exposureTime; // + QDateTime timestamp; // 时间戳 + + PositionsLogData(double target = 0, double actual = 0.0, double exposure = 0.0) + : targetPosition(target), actualPosition(actual), + exposureTime(exposure ), timestamp(QDateTime::currentDateTime()) { + } +}; + +// 协调控制器 +class OneMotorMultiPosCoordinator : public QObject +{ + Q_OBJECT +public: + OneMotorMultiPosCoordinator(IrisMultiMotorController* motorCtrl, + ImagerOperationBase* cameraCtrl, + QObject* parent = nullptr); + ~OneMotorMultiPosCoordinator(); + + QVector getAllPositionData() const; + bool saveToCsv(const QString& filename); + +public slots: + void startStepMotion(double speed, std::vector locations); + void stopStepMotion(); + +signals: + void progressChanged(int progress); + void sequenceComplete(int status); + void sequenceStopped(); + void errorOccurred(const QString& error); + void moveTo(int, double, double, int); + void getFocusIndexSobel(); + void zeroStart(int motorID); + + void hyperAutoExposureDoneSignal(double exposureTime); + +private slots: + void handlePositionReached(int motorID, double pos); + void handleCaptureComplete(double index); + void handleError(const QString& error); + void handleZeroComplete(int motorID, double pos); + +private: + void processNextPosition(); + void startMotionSequence(); + + IrisMultiMotorController* m_motorCtrl; + ImagerOperationBase* m_cameraCtrl; + QVector m_positionData; + mutable QMutex m_dataMutex; + + double m_currentPos; + bool m_isRunning; + double m_speed; + + int m_iStepInterval; + int m_iStepIntervalRealTime; + int m_counter; + bool m_isZeroing; + + std::vector m_locations; +}; diff --git a/HPPA/GonggaShanRecordCtl.cpp b/HPPA/GonggaShanRecordCtl.cpp index 352612e..b98e0ff 100644 --- a/HPPA/GonggaShanRecordCtl.cpp +++ b/HPPA/GonggaShanRecordCtl.cpp @@ -55,6 +55,7 @@ void GonggaShanRecordCtl::logStatus(const QString& message, bool isHearderBlankL GonggaShanRecordCtl::GonggaShanRecordCtl(QWidget* parent) : QDialog(parent) , m_taskScheduler(new GonggashanTaskScheduler(this)) + , m_taskExecutor(new GonggashanTaskExecutor(this)) { ui.setupUi(this); @@ -66,6 +67,20 @@ GonggaShanRecordCtl::GonggaShanRecordCtl(QWidget* parent) connect(ui.spinbox_Port, QOverload::of(&QSpinBox::valueChanged), [this](int value) { AppSettings::instance().setGonggaShanRecordPort(value); }); + + // 连接 GonggashanTaskExecutor 信号 + connect(m_taskExecutor, &GonggashanTaskExecutor::finished, + this, &GonggaShanRecordCtl::onTaskExecutorFinished); + + connect(m_taskExecutor, &GonggashanTaskExecutor::hyperAutoExposureSignal_gonggashan, + this, &GonggaShanRecordCtl::hyperAutoExposureSignal_gonggashan); + connect(this, &GonggaShanRecordCtl::hyperAutoExposureDoneSignal_gonggashan, + m_taskExecutor, &GonggashanTaskExecutor::onHyperExposureComplete); + + connect(m_taskExecutor, &GonggashanTaskExecutor::fiberExposureSignal, + this, &GonggaShanRecordCtl::fiberExposureSignal_gonggashan); + connect(this, &GonggaShanRecordCtl::fiberExposureDoneSignal_gonggashan, + m_taskExecutor, &GonggashanTaskExecutor::onFiberExposureComplete); } GonggaShanRecordCtl::~GonggaShanRecordCtl() @@ -112,18 +127,11 @@ void GonggaShanRecordCtl::stopListen() void GonggaShanRecordCtl::startRecord(int position) { - if (m_taskScheduler->isTaskRunning()) - { - logStatus("Data collection has begun...."); - - return; - } - QString pos = QString::number(position); logStatus("Reach pos: " + pos, true); m_taskScheduler->setTaskRunning(true); - emit startRcordSignal("pos_" + pos); + m_taskExecutor->start("pos_" + pos); } void GonggaShanRecordCtl::onFiberImagerStartExposureSignal() @@ -144,3 +152,262 @@ void GonggaShanRecordCtl::onRcordFinished() logStatus("Record Finished."); } + +void GonggaShanRecordCtl::onTaskExecutorFinished(bool success) +{ + qDebug() << "GonggaShanRecordCtl: TaskExecutor finished, success:" << success; + if (success) { + logStatus("Task completed successfully."); + } else { + logStatus("Task failed or stopped."); + } + m_taskScheduler->setTaskRunning(false); +} + +// ==================== GonggashanTaskExecutor 实现 ==================== + +GonggashanTaskExecutor::GonggashanTaskExecutor(QObject* parent) + : QObject(parent) + , m_machine(new QStateMachine(this)) +{ + buildStateMachine(); +} + +GonggashanTaskExecutor::~GonggashanTaskExecutor() +{ + if (m_machine) { + m_machine->stop(); + } +} + +void GonggashanTaskExecutor::buildStateMachine() +{ + // ---- 创建所有状态 ---- + m_hyperExposureState = new QState(QState::ExclusiveStates); + m_hyperExposureState->setObjectName("HyperExposure"); + + m_fiberExposureState = new QState(QState::ExclusiveStates); + m_fiberExposureState->setObjectName("FiberExposure"); + + m_gpsAcquisitionState = new QState(QState::ExclusiveStates); + m_gpsAcquisitionState->setObjectName("GpsAcquisition"); + + m_motorCalcState = new QState(QState::ExclusiveStates); + m_motorCalcState->setObjectName("MotorCalc"); + + m_dataCollectionState = new QState(QState::ExclusiveStates); + m_dataCollectionState->setObjectName("DataCollection"); + + m_finalState = new QFinalState(); + m_finalState->setObjectName("Completed"); + + // ---- HyperExposure 状态:等待外部硬件回调 ---- + connect(m_hyperExposureState, &QState::entered, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Enter m_hyperExposureState"; + emit hyperAutoExposureSignal_gonggashan(); + }); + connect(m_hyperExposureState, &QState::exited, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Exit m_hyperExposureState"; + leavePhase(m_hyperExposureState); + }); + QSignalTransition* hyperDone = new QSignalTransition(this, &GonggashanTaskExecutor::hyperExposureDone); + hyperDone->setTargetState(m_fiberExposureState); + m_hyperExposureState->addTransition(hyperDone); + + //m_hyperExposureState->addTransition(this, &GonggashanTaskExecutor::hyperExposureDone, m_fiberExposureState); + + // ---- FiberExposure 状态:等待外部硬件回调 ---- + connect(m_fiberExposureState, &QState::entered, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Enter m_fiberExposureState"; + emit fiberExposureSignal(); + }); + connect(m_fiberExposureState, &QState::exited, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Exit m_fiberExposureState"; + leavePhase(m_fiberExposureState); + }); + QSignalTransition* fiberDone = new QSignalTransition(this, &GonggashanTaskExecutor::fiberExposureDone); + fiberDone->setTargetState(m_gpsAcquisitionState); + m_fiberExposureState->addTransition(fiberDone); + + // ---- GpsAcquisition 状态:等待外部硬件回调 ---- + connect(m_gpsAcquisitionState, &QState::entered, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Enter m_gpsAcquisitionState"; + emit gpsAcquisitionSignal(); + }); + connect(m_gpsAcquisitionState, &QState::exited, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Exit m_gpsAcquisitionState"; + leavePhase(m_gpsAcquisitionState); + }); + QSignalTransition* gpsDone = new QSignalTransition(this, &GonggashanTaskExecutor::gpsAcquisitionDone); + gpsDone->setTargetState(m_motorCalcState); + m_gpsAcquisitionState->addTransition(gpsDone); + + // ---- MotorCalc 状态:等待外部硬件回调 ---- + connect(m_motorCalcState, &QState::entered, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Enter m_motorCalcState"; + }); + connect(m_motorCalcState, &QState::exited, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Exit m_motorCalcState"; + leavePhase(m_motorCalcState); + }); + QSignalTransition* motorDone = new QSignalTransition(this, &GonggashanTaskExecutor::motorSpeedDone); + motorDone->setTargetState(m_dataCollectionState); + m_motorCalcState->addTransition(motorDone); + + // ---- DataCollection 状态:同步阶段 ---- + connect(m_dataCollectionState, &QState::entered, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Enter m_dataCollectionState"; + if (dataCollectionImpl()) { + QTimer::singleShot(0, this, &GonggashanTaskExecutor::dataCollectionDone); + } + }); + connect(m_dataCollectionState, &QState::exited, this, [this]() { + qDebug() << "GonggashanTaskExecutor: Exit m_dataCollectionState"; + leavePhase(m_dataCollectionState); + }); + QSignalTransition* collDone = new QSignalTransition(this, &GonggashanTaskExecutor::dataCollectionDone); + collDone->setTargetState(m_finalState); + m_dataCollectionState->addTransition(collDone); + + // ---- FinalState:完成 ---- + connect(m_finalState, &QState::entered, this, &GonggashanTaskExecutor::onFinalStateEntered); + + // ---- stop() 可在任何状态下触发,直接跳转到 finalState ---- + QSignalTransition* stopTrans = new QSignalTransition(this, &GonggashanTaskExecutor::stopRequested); + stopTrans->setTargetState(m_finalState); + for (QState* s : { + m_hyperExposureState, + m_fiberExposureState, m_gpsAcquisitionState, m_motorCalcState, + m_dataCollectionState + }) { + s->addTransition(stopTrans); + } + + // ---- 设置状态机 ---- + m_machine->addState(m_hyperExposureState); + m_machine->addState(m_fiberExposureState); + m_machine->addState(m_gpsAcquisitionState); + m_machine->addState(m_motorCalcState); + m_machine->addState(m_dataCollectionState); + m_machine->addState(m_finalState); + + m_machine->setInitialState(m_hyperExposureState); + +} + +QState* GonggashanTaskExecutor::currentState() const +{ + if (!m_machine || m_machine->configuration().isEmpty()) { + return nullptr; + } + return qobject_cast(*m_machine->configuration().begin()); +} + +void GonggashanTaskExecutor::leavePhase(QState* state) +{ + Q_UNUSED(state); +} + +void GonggashanTaskExecutor::onFinalStateEntered() +{ + qDebug() << "GonggashanTaskExecutor: Final state entered, stopRequested:" << m_stopRequested; + emit finished(!m_stopRequested); + m_stopRequested = false; +} + +void GonggashanTaskExecutor::start(const QString& posInfo) +{ + if (isRunning()) { + qDebug() << "GonggashanTaskExecutor: Task is running, ignore new signal"; + return; + } + + m_machine->start(); + + m_posInfo = posInfo; + m_stopRequested = false; + qDebug() << "GonggashanTaskExecutor: Starting with pos:" << posInfo; + + QTimer::singleShot(0, this, [this, posInfo]() { + emit taskStartRequested(posInfo); + }); +} + +void GonggashanTaskExecutor::stop() +{ + if (!isRunning()) return; + m_stopRequested = true; + qDebug() << "GonggashanTaskExecutor: Stop requested"; + emit stopRequested(); +} + +void GonggashanTaskExecutor::onHyperExposureComplete(int exposureTime) +{ + if (currentState() != m_hyperExposureState) return; + m_hyperExposureTime = exposureTime; + hyperExposureImpl(exposureTime); + emit hyperExposureDone(); +} + +void GonggashanTaskExecutor::onFiberExposureComplete(int exposureTime) +{ + if (currentState() != m_fiberExposureState) return; + m_fiberExposureTime = exposureTime; + fiberExposureImpl(exposureTime); + emit fiberExposureDone(); +} + +void GonggashanTaskExecutor::onGpsAcquired(double latitude, double longitude, double altitude) +{ + if (currentState() != m_gpsAcquisitionState) return; + m_gpsData = QString("%1,%2,%3").arg(latitude).arg(longitude).arg(altitude); + gpsAcquisitionImpl(latitude, longitude, altitude); + emit gpsAcquisitionDone(); +} + +void GonggashanTaskExecutor::onMotorSpeedCalculated(double speed) +{ + if (currentState() != m_motorCalcState) return; + m_motorSpeed = speed; + emit motorSpeedSignal(speed); + if (motorCalcImpl()) { + emit motorSpeedDone(); + } +} + +bool GonggashanTaskExecutor::preparationImpl() +{ + qDebug() << "GonggashanTaskExecutor: Enter m_preparationState\n"; + return true; +} + +bool GonggashanTaskExecutor::hyperExposureImpl(int exposureTime) +{ + qDebug() << "GonggashanTaskExecutor: Hyper exposure complete, time:" << exposureTime; + return true; +} + +bool GonggashanTaskExecutor::fiberExposureImpl(int exposureTime) +{ + qDebug() << "GonggashanTaskExecutor: Fiber exposure complete, time:" << exposureTime; + return true; +} + +bool GonggashanTaskExecutor::gpsAcquisitionImpl(double lat, double lon, double alt) +{ + qDebug() << "GonggashanTaskExecutor: GPS acquired:" << lat << lon << alt; + return true; +} + +bool GonggashanTaskExecutor::motorCalcImpl() +{ + qDebug() << "GonggashanTaskExecutor: Motor speed calculated:" << m_motorSpeed; + return true; +} + +bool GonggashanTaskExecutor::dataCollectionImpl() +{ + qDebug() << "GonggashanTaskExecutor: Start data collection"; + emit startCollectionSignal(m_posInfo, m_gpsData); + return true; +} diff --git a/HPPA/GonggaShanRecordCtl.h b/HPPA/GonggaShanRecordCtl.h index 2289ebb..ca51bbf 100644 --- a/HPPA/GonggaShanRecordCtl.h +++ b/HPPA/GonggaShanRecordCtl.h @@ -10,12 +10,29 @@ #include #include #include +#include +#include +#include +#include #include "ui_gonggashanCtl.h" #include "CommunicationViaTCP.h" #include "AppSettings.h" +// ============ 执行阶段枚举 ============ +enum class GonggaShanExecPhase { + Idle, // 空闲 + Preparation, // 准备阶段 + HyperExposure, // 高光谱传感器曝光 + FiberExposure, // 光纤光谱仪曝光 + GpsAcquisition, // 获取GPS位置 + MotorCalc, // 计算马达速度 + DataCollection, // 开始采集:高光谱、FODIS、rgb相机 + Completed // 完成 +}; + +// ============ 任务调度器 ============ class GonggashanTaskScheduler : public QObject { Q_OBJECT @@ -40,6 +57,79 @@ private: TaskState m_taskState; }; +// ============ 任务执行器 ============ +class GonggashanTaskExecutor : public QObject +{ + Q_OBJECT + +public: + explicit GonggashanTaskExecutor(QObject* parent = nullptr); + ~GonggashanTaskExecutor(); + + bool isRunning() const { return m_machine && m_machine->isRunning() && !m_machine->configuration().isEmpty(); } + +public slots: + void start(const QString& posInfo); + void stop(); + + void onHyperExposureComplete(int exposureTime); + void onFiberExposureComplete(int exposureTime); + void onGpsAcquired(double latitude, double longitude, double altitude); + void onMotorSpeedCalculated(double speed); + +signals: + void hyperAutoExposureSignal_gonggashan(); + void fiberExposureSignal(); + void gpsAcquisitionSignal(); + void motorSpeedSignal(double speed); + void startCollectionSignal(const QString& posInfo, const QString& gpsData); + + void finished(bool success); + void errorOccurred(const QString& error); + + // ---- 以下为状态机内部信号,供 transition 使用 ---- + void taskStartRequested(const QString& posInfo); + void preparationComplete(); + void hyperExposureDone(); + void fiberExposureDone(); + void gpsAcquisitionDone(); + void motorSpeedDone(); + void dataCollectionDone(); + void stopRequested(); + +protected: + virtual bool preparationImpl(); + virtual bool hyperExposureImpl(int exposureTime); + virtual bool fiberExposureImpl(int exposureTime); + virtual bool gpsAcquisitionImpl(double lat, double lon, double alt); + virtual bool motorCalcImpl(); + virtual bool dataCollectionImpl(); + +private slots: + void onFinalStateEntered(); + +private: + void buildStateMachine(); + QState* currentState() const; + void leavePhase(QState* state); + + QString m_posInfo; + QString m_gpsData; + double m_motorSpeed = 0.0; + int m_hyperExposureTime = 0; + int m_fiberExposureTime = 0; + bool m_stopRequested = false; + + // Qt State Machine + QStateMachine* m_machine = nullptr; + QState* m_hyperExposureState = nullptr; + QState* m_fiberExposureState = nullptr; + QState* m_gpsAcquisitionState = nullptr; + QState* m_motorCalcState = nullptr; + QState* m_dataCollectionState = nullptr; + QFinalState* m_finalState = nullptr; +}; + class GonggaShanRecordCtl : public QDialog { Q_OBJECT @@ -55,6 +145,12 @@ public Q_SLOTS: void onFiberImagerExposureCompleteSignal(int exposureTime); Q_SIGNALS: + void hyperAutoExposureSignal_gonggashan(); + void hyperAutoExposureDoneSignal_gonggashan(double exposureTime); + + void fiberExposureSignal_gonggashan(); + void fiberExposureDoneSignal_gonggashan(double exposureTime); + // Emitted when user changes any of the R/G/B wavelength values void startRcordSignal(QString posInfo); @@ -64,12 +160,16 @@ private Q_SLOTS: void startRecord(int position); + // GonggashanTaskExecutor 反馈槽 + void onTaskExecutorFinished(bool success); + private: void logStatus(const QString& message, bool isHearderBlankLine = false, bool isTailBlankLine = false); Ui::gongga_control ui; QPointer tcpServer6005; GonggashanTaskScheduler* m_taskScheduler; + GonggashanTaskExecutor* m_taskExecutor; // 新增 QString m_logFilePath; QFile m_logFile; QTextStream m_logStream; diff --git a/HPPA/HPPA.cpp b/HPPA/HPPA.cpp index 610f015..540aaca 100644 --- a/HPPA/HPPA.cpp +++ b/HPPA/HPPA.cpp @@ -1112,16 +1112,40 @@ void HPPA::initControlTabwidget() void HPPA::setupGonggashanAutoRecordConnection() { - connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::startRcordSignal, this, &HPPA::onGonggashanRecord); + connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::hyperAutoExposureSignal_gonggashan, this, &HPPA::onGonggashanHyperAutoExposure); + connect(m_omc, &OneMotorControl::hyperAutoExposureDoneSignal_gonggashan, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::hyperAutoExposureDoneSignal_gonggashan); + + connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::fiberExposureSignal_gonggashan, this, &HPPA::onGonggashanFiberAutoExposure); + connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::fiberExposureDoneSignal_gonggashan); connect(m_fodisWindow, &FodisWindow::startExposureSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onFiberImagerStartExposureSignal); connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, this, &HPPA::onStartRecordStep1); connect(m_fodisWindow, &FodisWindow::exposureCompleteSignal, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onFiberImagerExposureCompleteSignal); + connect(m_gonggaShanRecordCtl, &GonggaShanRecordCtl::startRcordSignal, this, &HPPA::onGonggashanRecord); connect(m_omc, &OneMotorControl::sequenceComplete, m_fodisWindow, &FodisWindow::closeFiberImager); connect(m_omc, &OneMotorControl::sequenceComplete, m_gonggaShanRecordCtl, &GonggaShanRecordCtl::onRcordFinished); } +void HPPA::onGonggashanHyperAutoExposure() +{ + //连接马达和光谱仪 + m_omc->connectMotor(false); + + if (!testImagerVality()) + { + onconnect(); + } + + m_omc->setImager(m_Imager); + m_omc->multiPosHyperAutoExposure(); +} + +void HPPA::onGonggashanFiberAutoExposure() +{ + //m_fodisWindow->openFiberImager_expose_record(posInfo); +} + void HPPA::onGonggashanRecord(QString posInfo) { //设置文件名 diff --git a/HPPA/HPPA.h b/HPPA/HPPA.h index 339a2dd..36877fc 100644 --- a/HPPA/HPPA.h +++ b/HPPA/HPPA.h @@ -458,6 +458,8 @@ public Q_SLOTS: void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error); void onGonggashanRecord(QString posInfo); + void onGonggashanHyperAutoExposure(); + void onGonggashanFiberAutoExposure(); protected: void closeEvent(QCloseEvent* event) override; diff --git a/HPPA/ImagerOperationBase.cpp b/HPPA/ImagerOperationBase.cpp index 0de74b1..4c3bda1 100644 --- a/HPPA/ImagerOperationBase.cpp +++ b/HPPA/ImagerOperationBase.cpp @@ -68,11 +68,12 @@ double ImagerOperationBase::auto_exposure() imagerStopCollect(); - emit autoExposureSignal(); + double exposureTime = getIntegrationTime(); + emit autoExposureSignal(exposureTime); - //std::cout << "自动曝光:" << getIntegrationTime() << std::endl; + //std::cout << "自动曝光:" << exposureTime << std::endl; - return getIntegrationTime(); + return exposureTime; } void ImagerOperationBase::focus() diff --git a/HPPA/ImagerOperationBase.h b/HPPA/ImagerOperationBase.h index b6e16fa..77adf6e 100644 --- a/HPPA/ImagerOperationBase.h +++ b/HPPA/ImagerOperationBase.h @@ -117,7 +117,7 @@ signals: void testImagerStatus();//表示可以测试相机连接状态:是否连接,并反映到界面上 - void autoExposureSignal(); + void autoExposureSignal(double exposureTime); // 新增:当一组影像文件(.bil/.hdr)写入完成后发出(会从采集线程发出,Qt 会做 queued connection) void ImageFileSaved(const QString& path, int fileIndex); diff --git a/HPPA/OneMotorControl.cpp b/HPPA/OneMotorControl.cpp index a66ffa5..7cd27f0 100644 --- a/HPPA/OneMotorControl.cpp +++ b/HPPA/OneMotorControl.cpp @@ -248,6 +248,34 @@ void OneMotorControl::stop() emit stopStepMotionSignal(); } +void OneMotorControl::multiPosHyperAutoExposure() +{ + //所有该自动曝光的位置 + std::vector maxRangeLocations = m_multiAxisController->getMaxPos(); + double maxPos = maxRangeLocations[0]; + + std::vector locations; + locations.push_back(maxPos * 0.2); + locations.push_back(maxPos * 0.5); + locations.push_back(maxPos * 0.8); + + //创建协调器,并连接信号槽 + m_coordinator_gonggashan_autoexpose = new OneMotorMultiPosCoordinator(m_multiAxisController, m_Imager); + + //connect(this, SIGNAL(stopStepMotionSignal()), m_coordinator_gonggashan_autoexpose, SLOT(stopStepMotion())); + connect(m_coordinator_gonggashan_autoexpose, &OneMotorMultiPosCoordinator::sequenceComplete, this, &OneMotorControl::onSequenceComplete_gonggashan_autoexpose); + connect(m_coordinator_gonggashan_autoexpose, &OneMotorMultiPosCoordinator::hyperAutoExposureDoneSignal, this, &OneMotorControl::hyperAutoExposureDoneSignal_gonggashan); + + m_coordinator_gonggashan_autoexpose->startStepMotion(ui.speed_lineEdit->text().toDouble(), locations); +} + +void OneMotorControl::onSequenceComplete_gonggashan_autoexpose(int state) +{ + emit sequenceComplete(); + + m_coordinator_gonggashan_autoexpose->deleteLater(); +} + void OneMotorControl::onSequenceComplete(int state) { emit sequenceComplete(); diff --git a/HPPA/OneMotorControl.h b/HPPA/OneMotorControl.h index 1900363..7a02235 100644 --- a/HPPA/OneMotorControl.h +++ b/HPPA/OneMotorControl.h @@ -26,6 +26,8 @@ public: void run(); void stop(); + void multiPosHyperAutoExposure(); + void record_dark(); void record_white(); @@ -47,6 +49,7 @@ public Q_SLOTS: void onxMotorStop(); void onSequenceComplete(int state); + void onSequenceComplete_gonggashan_autoexpose(int state); signals: void moveSignal(int, bool, double, int); @@ -65,6 +68,8 @@ signals: void broadcastLocationSignal(std::vector); + void hyperAutoExposureDoneSignal_gonggashan(double exposureTime); + private: Ui::OneMotorControl_UI ui; @@ -78,6 +83,8 @@ private: DarkAndWhiteCaptureCoordinator* m_whiteCaptureCoordinator = nullptr; bool m_xMotorConnectionStatus = false; + + QPointer m_coordinator_gonggashan_autoexpose; }; class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase diff --git a/HPPA/ResononNirImager.cpp b/HPPA/ResononNirImager.cpp index 3a6cf90..1ba3496 100644 --- a/HPPA/ResononNirImager.cpp +++ b/HPPA/ResononNirImager.cpp @@ -128,9 +128,12 @@ double ResononNirImager::auto_exposure() reConnectImage(); //imagerStopCollect(); - //std::cout << "自动曝光:" << getIntegrationTime() << std::endl; + double exposureTime = getIntegrationTime(); + emit autoExposureSignal(exposureTime); - return getIntegrationTime(); + //std::cout << "自动曝光:" << exposureTime << std::endl; + + return exposureTime; } double ResononNirImager::getWavelengthAtBand(int band)