add,计划采集19,上海农科院3D植物表型:

1、新增任务类型LiftingPlatform:基于深度相机探测的植被深度,调整升降台的高度;
This commit is contained in:
tangchao0503
2026-08-12 15:13:24 +08:00
parent abdb27b228
commit 33e34aa125
12 changed files with 185 additions and 25 deletions

View File

@ -879,3 +879,96 @@ bool TwoMotor1PosCoordinator::checkArrival()
{
return m_xReached && m_yReached;
}
//---------------------------------------------------------------------------------------------------------------------------------------------
OneMotionCoordinator::OneMotionCoordinator(IrisMultiMotorController* motorCtrl, QObject* parent)
: QObject(parent)
, m_motorCtrl(motorCtrl)
, m_targetPosition(0)
, m_speed(0)
, m_actualPosition(0)
, m_isMoving(false)
, m_retryTimes(0)
, m_reached(false)
{
connect(this, SIGNAL(moveTo(int, double, double, int)), m_motorCtrl, SLOT(moveTo(int, double, double, int)));
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal, this, &OneMotionCoordinator::handlePositionReached);
}
OneMotionCoordinator::~OneMotionCoordinator()
{
}
void OneMotionCoordinator::moveToTarget(double position, double speed)
{
QMutexLocker locker(&m_dataMutex);
m_targetPosition = position;
m_speed = speed;
m_retryTimes = 0;
m_reached = false;
m_isMoving = true;
qDebug() << "OneMotionCoordinator: moving to" << position;
emit moveTo(0, position, speed, 1000);
}
void OneMotionCoordinator::handlePositionReached(int motorID, double position)
{
if (!m_isMoving || motorID != 0)
{
return;
}
QMutexLocker locker(&m_dataMutex);
m_actualPosition = position;
double errorRate = getErrorRate(m_targetPosition, m_actualPosition);
if (errorRate > 5 && m_retryTimes < m_retryLimit)
{
m_retryTimes++;
qDebug() << "OneMotionCoordinator: retry" << m_retryTimes << ", target:" << m_targetPosition << ", actual:" << m_actualPosition;
emit moveTo(0, m_targetPosition, m_speed, 1000);
return;
}
m_retryTimes = 0;
m_reached = true;
m_isMoving = false;
qDebug() << "OneMotionCoordinator: Arrived at" << m_actualPosition;
emit sequenceComplete(0);
emit ArrivalSignal(m_actualPosition);
}
double OneMotionCoordinator::getErrorRate(double targetLoc, double actualLoc)
{
double targetLocTmp;
if (targetLoc == 0)
{
targetLocTmp = 0.001;
}
else
{
targetLocTmp = targetLoc;
}
double errorRate = abs(targetLoc - actualLoc) / targetLocTmp * 100;
return errorRate;
}

View File

@ -265,3 +265,38 @@ private:
bool m_xReached;
bool m_yReached;
};
class OneMotionCoordinator : public QObject
{
Q_OBJECT
public:
OneMotionCoordinator(IrisMultiMotorController* motorCtrl, QObject* parent = nullptr);
~OneMotionCoordinator();
public slots:
void moveToTarget(double position, double speed);
signals:
void sequenceComplete(int status);
void ArrivalSignal(double position);
void moveTo(int, double, double, int);
private slots:
void handlePositionReached(int motorID, double position);
private:
bool checkArrival();
double getErrorRate(double targetLoc, double actualLoc);
IrisMultiMotorController* m_motorCtrl;
mutable QMutex m_dataMutex;
double m_targetPosition;
double m_speed;
double m_actualPosition;
bool m_isMoving;
int m_retryLimit = 3;
int m_retryTimes;
bool m_reached;
};

View File

@ -659,6 +659,7 @@ void HPPA::initTimedDataCollection()
m_tdc->setAttribute(Qt::WA_DeleteOnClose);
m_tmc->connectMotor(false);
m_omc_LiftingPlatform->connectMotor(false);
// 定时采集控制器 → 相机/马达
connect(m_tdc, &TimedDataCollection::hyperCamParm, this, &HPPA::setTimedDataCollectionHyperCamParm);
@ -667,7 +668,7 @@ void HPPA::initTimedDataCollection()
connect(m_tdc, &TimedDataCollection::startRecordSignal, this, &HPPA::onStartTimedDataCollection);
connect(m_tdc, &TimedDataCollection::ObtainingDepthInformationSignals, this, &HPPA::onObtainTargetDepthInformation);
connect(m_tdc, &TimedDataCollection::switchHalogenLampSignal, m_pc3D, &PowerControl3D::switchHalogenLampPower);
connect(m_tdc, &TimedDataCollection::switchD65LampSignal, m_pc3D, &PowerControl3D::switchD65LampPower);
connect(m_tdc, &TimedDataCollection::switchSlrSignal, m_pc3D, &PowerControl3D::switchSlrPower);
@ -676,6 +677,11 @@ void HPPA::initTimedDataCollection()
connect(m_tmc, &TwoMotorControl::sequenceComplete, m_tdc, &TimedDataCollection::subTaskCompleted);
connect(m_tmc, &TwoMotorControl::back2OriginSignal_TimedDataCollection, m_tdc, &TimedDataCollection::onBack2Origin);
//升降台
connect(m_tdc, &TimedDataCollection::LiftingPlatformSignals, this, &HPPA::onLiftingPlatform);
connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::sequenceComplete, m_tdc, &TimedDataCollection::subTaskCompleted);
connect(m_omc_LiftingPlatform, &OneMotorControl_LiftingPlatform::back2OriginSignal_TimedDataCollection, m_tdc, &TimedDataCollection::onBack2Origin);
m_tdc->show();
}
@ -779,6 +785,11 @@ void HPPA::onObtainTargetDepthInformation(SubTask subTaskParams)
m_tmc->run4_ObtainTargetDepthInfo(m_depthCameraWindow, subTaskParams.depthType, subTaskParams.depthInfoX, subTaskParams.depthInfoY, subTaskParams.averageNumberOfTimes, subTaskParams.percentageOfEffectiveArea);
}
void HPPA::onLiftingPlatform(SubTask subTaskParams)
{
m_omc_LiftingPlatform->run();
}
void HPPA::onTimedDataCollection()
{
QAction* checkedScenario = m_ScenarioActionGroup->checkedAction();

View File

@ -451,6 +451,7 @@ public Q_SLOTS:
void setTimedDataCollectionMotorParm(QString pathLineFilePath);
void onStartTimedDataCollection(int camType);
void onObtainTargetDepthInformation(SubTask subTaskParams);
void onLiftingPlatform(SubTask subTaskParams);
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error);

View File

@ -509,11 +509,20 @@ void OneMotorControl_LiftingPlatform::onxMotorStop()
void OneMotorControl_LiftingPlatform::run()
{
if (m_coordinator)//当高光谱相机停止采集后马达还未回到原点时上次任务的m_coordinator还没有被销毁
m_coordinator = new OneMotionCoordinator(m_multiAxisController,this);
connect(m_coordinator, &OneMotionCoordinator::sequenceComplete, this, &OneMotorControl_LiftingPlatform::sequenceComplete);
connect(m_coordinator, &OneMotionCoordinator::ArrivalSignal, this, &OneMotorControl_LiftingPlatform::onBack2Origin);
double plantDepthValue = DepthValueLogger::instance().readLatestPlantDepthValue();
double liftingPlatformDepthValue = DepthValueLogger::instance().readLatestLiftingPlatformDepthValue();
double targetDepth = liftingPlatformDepthValue - plantDepthValue;
if (targetDepth < 0)
{
onSequenceComplete(0);
return;
}
m_coordinator->moveToTarget(targetDepth, ui.speed_lineEdit->text().toDouble());
}
void OneMotorControl_LiftingPlatform::stop()
@ -521,17 +530,10 @@ void OneMotorControl_LiftingPlatform::stop()
emit stopStepMotionSignal();
}
void OneMotorControl_LiftingPlatform::onSequenceComplete(int state)
void OneMotorControl_LiftingPlatform::onBack2Origin(double pos)
{
emit sequenceComplete();
emit back2OriginSignal_TimedDataCollection();
disconnect(this, SIGNAL(start(OneMotionCapturePathLine)), m_coordinator, SLOT(startStepMotion(OneMotionCapturePathLine)));
disconnect(this, SIGNAL(stopStepMotionSignal()), m_coordinator, SLOT(stopStepMotion()));
disconnect(m_coordinator, SIGNAL(sequenceComplete(int)), this, SLOT(onSequenceComplete(int)));
// Use deleteLater() instead of delete: this slot may have been called directly
// from OneMotionCaptureCoordinator's call stack (direct connection), so deleting
// the object here would cause a crash when execution returns to the destroyed object.
m_coordinator->deleteLater();
m_coordinator = nullptr;
}

View File

@ -11,6 +11,8 @@
#include "MotorWindowBase.h"
#include "AppSettings.h"
#include "DepthValueLogger.h"
class OneMotorControl : public QDialog, public MotorWindowBase
{
Q_OBJECT
@ -106,7 +108,7 @@ public Q_SLOTS:
void onxMotorLeft();
void onxMotorStop();
void onSequenceComplete(int state);
void onBack2Origin(double pos);
signals:
void moveSignal(int, bool, double, int);
@ -121,7 +123,8 @@ signals:
void start(OneMotionCapturePathLine);
void stopStepMotionSignal();
void sequenceComplete();
void sequenceComplete(int status);
void back2OriginSignal_TimedDataCollection();
void broadcastLocationSignal(std::vector<double>);
@ -131,7 +134,7 @@ private:
QThread m_motorThread;
IrisMultiMotorController* m_multiAxisController = nullptr;
QPointer<OneMotionCaptureCoordinator> m_coordinator;
QPointer<OneMotionCoordinator> m_coordinator;
bool m_xMotorConnectionStatus = false;
};

View File

@ -587,15 +587,17 @@ QString TaskTreeModel::statusToString(TaskStatus status) const
QString TaskTreeModel::subTaskTypeToString(SubTaskType type) const
{
switch (type) {
case SubTaskType::HyperSpectual400_1000nm: return QString::fromLocal8Bit("高光谱 400-1000nm");
case SubTaskType::HyperSpectual1000_1700nm: return QString::fromLocal8Bit("高光谱 1000-1700nm");
case SubTaskType::SingleLensReflex: return QString::fromLocal8Bit("单反相机");
case SubTaskType::DepthCamera: return QString::fromLocal8Bit("深度相机");
case SubTaskType::ObtainingDepthInformation: return QString::fromLocal8Bit("探测深度信息");
case SubTaskType::AutoFocus: return QString::fromLocal8Bit("自动调焦");
switch (type)
{
case SubTaskType::HyperSpectual400_1000nm: return QString::fromLocal8Bit("高光谱 400-1000nm");
case SubTaskType::HyperSpectual1000_1700nm: return QString::fromLocal8Bit("高光谱 1000-1700nm");
case SubTaskType::SingleLensReflex: return QString::fromLocal8Bit("单反相机");
case SubTaskType::DepthCamera: return QString::fromLocal8Bit("深度相机");
case SubTaskType::ObtainingDepthInformation: return QString::fromLocal8Bit("探测深度信息");
case SubTaskType::AutoFocus: return QString::fromLocal8Bit("自动调焦");
case SubTaskType::LiftingPlatform: return QString::fromLocal8Bit("升降平台");
}
return "未知类型";
return QString::fromLocal8Bit("未知类型");
}
QString TaskTreeModel::formatDuration(double minutes) const

View File

@ -113,6 +113,7 @@ void TimedDataCollection::setupConnections()
this, &TimedDataCollection::startRecordSignal);
connect(m_scheduler, &TaskScheduler::ObtainingDepthInformationSignals, this, &TimedDataCollection::ObtainingDepthInformationSignals);
connect(m_scheduler, &TaskScheduler::LiftingPlatformSignals, this, &TimedDataCollection::LiftingPlatformSignals);
connect(m_scheduler, &TaskScheduler::switchHalogenLampSignal,
this, &TimedDataCollection::switchHalogenLampSignal);

View File

@ -53,6 +53,7 @@ Q_SIGNALS:
void startRecordSignal(int camType);
void ObtainingDepthInformationSignals(SubTask info);
void LiftingPlatformSignals(SubTask info);
void switchHalogenLampSignal(int state);
void switchD65LampSignal(int state);

View File

@ -116,6 +116,7 @@ SubTaskType TimedDataCollectionDataStructuresReaderWriter::stringToSubTaskType(c
if (str == "ObtainingDepthInformation") return SubTaskType::ObtainingDepthInformation;
if (str == "AutoFocus") return SubTaskType::AutoFocus;
if (str == "LiftingPlatform") return SubTaskType::LiftingPlatform;
return SubTaskType::SingleLensReflex;
}
@ -479,6 +480,12 @@ void TaskExecutor::executeNextSubTask()
//执行自动调焦任务
break;
}
case SubTaskType::LiftingPlatform:
{
//执行升降平台任务
emit LiftingPlatformSignals(subTask);
break;
}
case SubTaskType::HyperSpectual400_1000nm:
{
m_camType = 0;
@ -721,6 +728,7 @@ void TaskScheduler::executeTask(TimedTask& task)
this, &TaskScheduler::startRecordSignal);
connect(m_currentExecutor, &TaskExecutor::ObtainingDepthInformationSignals, this, &TaskScheduler::ObtainingDepthInformationSignals);
connect(m_currentExecutor, &TaskExecutor::LiftingPlatformSignals, this, &TaskScheduler::LiftingPlatformSignals);
connect(m_currentExecutor, &TaskExecutor::switchHalogenLampSignal, this, &TaskScheduler::switchHalogenLampSignal);
connect(m_currentExecutor, &TaskExecutor::switchD65LampSignal, this, &TaskScheduler::switchD65LampSignal);

View File

@ -27,7 +27,8 @@ enum class SubTaskType {
SingleLensReflex, // 单反相机
DepthCamera, // 深度相机采集任务
ObtainingDepthInformation, //通过深度相机获取被测物体的深度信息
AutoFocus // 自动对焦
AutoFocus, // 自动对焦
LiftingPlatform // 升降平台
};
// ==================== 统一子任务封装 ====================
@ -166,6 +167,7 @@ signals:
void startRecordSignal(int camType);
void ObtainingDepthInformationSignals(SubTask info);
void LiftingPlatformSignals(SubTask info);
void switchHalogenLampSignal(int state);
void switchD65LampSignal(int state);
@ -237,6 +239,7 @@ signals:
void startRecordSignal(int camType);
void ObtainingDepthInformationSignals(SubTask info);
void LiftingPlatformSignals(SubTask info);
void switchHalogenLampSignal(int state);
void switchD65LampSignal(int state);

View File

@ -222,7 +222,7 @@ void TwoMotorControl::run4_ObtainTargetDepthInfo(DepthCameraWindow* window, int
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::back2origin);
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, this, &TwoMotorControl::sequenceComplete, Qt::UniqueConnection);//关灯
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, this, &TwoMotorControl::saveDepthValue, Qt::UniqueConnection);//控制白板平台升降
connect(window->m_DepthCameraOperation, &DepthCameraOperation::DepthValueSignal, this, &TwoMotorControl::saveDepthValue, Qt::UniqueConnection);
connect(m_ObtainTargetDepthInfoCoordinator, &TwoMotor1PosCoordinator::back2OriginSignal, this, &TwoMotorControl::onBack2Origin3);