add,计划采集19,上海农科院3D植物表型:
1、新增任务类型LiftingPlatform:基于深度相机探测的植被深度,调整升降台的高度;
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user