完成新的二轴采集:二轴采集逻辑控制器
This commit is contained in:
443
HPPA/CaptureCoordinator.cpp
Normal file
443
HPPA/CaptureCoordinator.cpp
Normal file
@ -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<double>, const std::vector<double>, int)),
|
||||||
|
m_motorCtrl, SLOT(moveTo(const std::vector<double>, const std::vector<double>, 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<double>, const std::vector<double>, int)),
|
||||||
|
m_motorCtrl, SLOT(moveTo(const std::vector<double>, const std::vector<double>, int)));
|
||||||
|
|
||||||
|
connect(m_motorCtrl, &IrisMultiMotorController::motorStopSignal,
|
||||||
|
this, &TwoMotionCaptureCoordinator::handlePositionReached);
|
||||||
|
//connect(m_motorCtrl, &IrisMultiMotorController::moveFailed,
|
||||||
|
// this, &TwoMotionCaptureCoordinator::handleError);
|
||||||
|
}
|
||||||
|
|
||||||
|
TwoMotionCaptureCoordinator::~TwoMotionCaptureCoordinator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TwoMotionCaptureCoordinator::start(QVector<PathLine> 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<double> 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<double> 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<PathLine> 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<double> loc;
|
||||||
|
loc.push_back(tmp.targetXMinPosition);
|
||||||
|
loc.push_back(tmp.targetYPosition);
|
||||||
|
std::vector<double> speed;
|
||||||
|
speed.push_back(tmp.speedTargetXMinPosition);
|
||||||
|
speed.push_back(tmp.speedTargetYPosition);
|
||||||
|
|
||||||
|
m_isMoving2YTargeLoc = true;
|
||||||
|
m_isMoving2XMin = true;
|
||||||
|
emit moveTo(loc, speed, 1000);
|
||||||
|
}
|
107
HPPA/CaptureCoordinator.h
Normal file
107
HPPA/CaptureCoordinator.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
#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<PathLine>);
|
||||||
|
|
||||||
|
class TwoMotionCaptureCoordinator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TwoMotionCaptureCoordinator(IrisMultiMotorController* motorCtrl,
|
||||||
|
ImagerOperationBase* cameraCtrl,
|
||||||
|
QObject* parent = nullptr);
|
||||||
|
TwoMotionCaptureCoordinator(IrisMultiMotorController* motorCtrl,
|
||||||
|
QObject* parent = nullptr);
|
||||||
|
~TwoMotionCaptureCoordinator();
|
||||||
|
|
||||||
|
QVector<PathLine> 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<double>, const std::vector<double>, int);
|
||||||
|
void stopMotorSignal(int axis);
|
||||||
|
|
||||||
|
void recordState(bool state);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void start(QVector<PathLine> 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<PathLine> 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<double> m_locBeforeStart;
|
||||||
|
|
||||||
|
bool m_isMoving2XStartLoc;
|
||||||
|
bool m_isMoving2YStartLoc;
|
||||||
|
|
||||||
|
int m_numCurrentPathLine;
|
||||||
|
};
|
@ -311,6 +311,18 @@ HPPA::HPPA(QWidget *parent)
|
|||||||
tabifyDockWidget(dock_rac, dock_omc);
|
tabifyDockWidget(dock_rac, dock_omc);
|
||||||
mPanelMenu->addAction(dock_omc->toggleViewAction());
|
mPanelMenu->addAction(dock_omc->toggleViewAction());
|
||||||
|
|
||||||
|
//2<><32><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
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<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"), 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();
|
createActionGroups();
|
||||||
connect(mImagerGroup, &QActionGroup::triggered, this, &HPPA::selectingImager);
|
connect(mImagerGroup, &QActionGroup::triggered, this, &HPPA::selectingImager);
|
||||||
|
|
||||||
@ -363,7 +375,6 @@ void HPPA::recordFromRobotArm(int fileCounter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
onCreateTab(fileCounter-1);
|
onCreateTab(fileCounter-1);
|
||||||
m_numberOfRecording = fileCounter - 1;
|
|
||||||
emit StartRecordSignal();
|
emit StartRecordSignal();
|
||||||
|
|
||||||
ui.action_start_recording->setText(QString::fromLocal8Bit("<EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD>"));
|
ui.action_start_recording->setText(QString::fromLocal8Bit("<EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD>"));
|
||||||
@ -419,6 +430,7 @@ void HPPA::createMoveplatformActionGroup()
|
|||||||
moveplatformActionGroup->addAction(ui.mAction_2AxisMotor);
|
moveplatformActionGroup->addAction(ui.mAction_2AxisMotor);
|
||||||
moveplatformActionGroup->addAction(ui.mAction_RobotArm);
|
moveplatformActionGroup->addAction(ui.mAction_RobotArm);
|
||||||
moveplatformActionGroup->addAction(ui.mAction_1AxisMotor);
|
moveplatformActionGroup->addAction(ui.mAction_1AxisMotor);
|
||||||
|
moveplatformActionGroup->addAction(ui.mAction_2AxisMotor_new);
|
||||||
|
|
||||||
// <20><>ȡ<EFBFBD>ϴ<EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>
|
// <20><>ȡ<EFBFBD>ϴ<EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
@ -441,6 +453,10 @@ void HPPA::createMoveplatformActionGroup()
|
|||||||
{
|
{
|
||||||
ui.mAction_1AxisMotor->setChecked(true);
|
ui.mAction_1AxisMotor->setChecked(true);
|
||||||
}
|
}
|
||||||
|
else if (lastSelectedAction == "mAction_2AxisMotor_new")
|
||||||
|
{
|
||||||
|
ui.mAction_2AxisMotor_new->setChecked(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HPPA::selectingMoveplatform(QAction* selectedAction)
|
void HPPA::selectingMoveplatform(QAction* selectedAction)
|
||||||
@ -562,6 +578,7 @@ void HPPA::onStartRecordStep1()
|
|||||||
string directory = fileOperation->getDirectoryFromString();
|
string directory = fileOperation->getDirectoryFromString();
|
||||||
//string imgPath = directory + "\\tmp_image";
|
//string imgPath = directory + "\\tmp_image";
|
||||||
string imgPath = directory + "\\" + m_FilenameLineEdit->text().toStdString();
|
string imgPath = directory + "\\" + m_FilenameLineEdit->text().toStdString();
|
||||||
|
string x_location = removeFileExtension(imgPath) + "_x_location.pos";
|
||||||
|
|
||||||
m_RecordState += 1;
|
m_RecordState += 1;
|
||||||
if (m_RecordState % 2 == 1)
|
if (m_RecordState % 2 == 1)
|
||||||
@ -599,7 +616,6 @@ void HPPA::onStartRecordStep1()
|
|||||||
ui.ImageViewerTabWidget->clear();
|
ui.ImageViewerTabWidget->clear();
|
||||||
|
|
||||||
onCreateTab(0);
|
onCreateTab(0);
|
||||||
m_numberOfRecording = 0;
|
|
||||||
|
|
||||||
m_Imager->setFileName2Save(imgPath);
|
m_Imager->setFileName2Save(imgPath);
|
||||||
m_Imager->setFrameNumber(this->frame_number->text().toInt());
|
m_Imager->setFrameNumber(this->frame_number->text().toInt());
|
||||||
@ -627,7 +643,6 @@ void HPPA::onStartRecordStep1()
|
|||||||
ui.ImageViewerTabWidget->clear();
|
ui.ImageViewerTabWidget->clear();
|
||||||
|
|
||||||
onCreateTab(0);
|
onCreateTab(0);
|
||||||
m_numberOfRecording = 0;
|
|
||||||
|
|
||||||
ui.action_start_recording->setText(QString::fromLocal8Bit("ֹͣ<EFBFBD>ɼ<EFBFBD>"));
|
ui.action_start_recording->setText(QString::fromLocal8Bit("ֹͣ<EFBFBD>ɼ<EFBFBD>"));
|
||||||
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(255,0,0);}");
|
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(255,0,0);}");
|
||||||
@ -686,8 +701,6 @@ void HPPA::onStartRecordStep1()
|
|||||||
//ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>tab
|
//ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>tab
|
||||||
ui.ImageViewerTabWidget->clear();
|
ui.ImageViewerTabWidget->clear();
|
||||||
|
|
||||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼x<C2BC><78><EFBFBD><EFBFBD>λ<EFBFBD>õ<EFBFBD><C3B5>ļ<EFBFBD>
|
|
||||||
string x_location = removeFileExtension(imgPath) + "x_location.pos";
|
|
||||||
m_hTimesFile = fopen(x_location.c_str(), "w+");
|
m_hTimesFile = fopen(x_location.c_str(), "w+");
|
||||||
|
|
||||||
m_Imager->setFileName2Save(imgPath);
|
m_Imager->setFileName2Save(imgPath);
|
||||||
@ -721,6 +734,35 @@ void HPPA::onStartRecordStep1()
|
|||||||
|
|
||||||
return;
|
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("ֹͣ<EFBFBD>ɼ<EFBFBD>"));
|
||||||
|
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("<EFBFBD>ɼ<EFBFBD>"));
|
||||||
|
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(0,255,0);}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
else if (checkedName == "mAction_RobotArm")
|
else if (checkedName == "mAction_RobotArm")
|
||||||
{
|
{
|
||||||
//<2F><><EFBFBD>ж<EFBFBD><D0B6>Ƿ<EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>к<EFBFBD><D0BA><EFBFBD>RobotArmControl::executeTask<73><6B><EFBFBD><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾbug
|
//<2F><><EFBFBD>ж<EFBFBD><D0B6>Ƿ<EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>к<EFBFBD><D0BA><EFBFBD>RobotArmControl::executeTask<73><6B><EFBFBD><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾbug
|
||||||
@ -790,6 +832,8 @@ void HPPA::onCreateTab(int trackNumber)
|
|||||||
{
|
{
|
||||||
if (trackNumber >= 0)
|
if (trackNumber >= 0)
|
||||||
{
|
{
|
||||||
|
m_numberOfRecording = trackNumber;
|
||||||
|
|
||||||
QWidget * tabTmp = new QWidget();
|
QWidget * tabTmp = new QWidget();
|
||||||
|
|
||||||
QGridLayout *GridLayout = new QGridLayout();
|
QGridLayout *GridLayout = new QGridLayout();
|
||||||
@ -1755,6 +1799,13 @@ void HPPA::getRequest(QString str)
|
|||||||
|
|
||||||
void HPPA::newMotor()
|
void HPPA::newMotor()
|
||||||
{
|
{
|
||||||
|
QAction* checked = moveplatformActionGroup->checkedAction();
|
||||||
|
QString checkedName = checked->objectName();
|
||||||
|
if (checkedName != "mAction_2AxisMotor")
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_xMotor != nullptr && m_yMotor != nullptr)
|
if (m_xMotor != nullptr && m_yMotor != nullptr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -1932,7 +1983,7 @@ void HPPA::onconnect()
|
|||||||
|
|
||||||
m_Imager->connect_imager(frame_number->text().toInt());
|
m_Imager->connect_imager(frame_number->text().toInt());
|
||||||
m_Imager->setFileName2Save(m_FilenameLineEdit->text().toStdString());
|
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_WhenFrameNumberMeet()), this, SLOT(onRecordFinishedSignal_WhenFrameNumberMeet()));
|
||||||
connect(m_Imager, SIGNAL(RecordFinishedSignal_WhenFrameNumberNotMeet()), this, SLOT(onRecordFinishedSignal_WhenFrameNumberNotMeet()));
|
connect(m_Imager, SIGNAL(RecordFinishedSignal_WhenFrameNumberNotMeet()), this, SLOT(onRecordFinishedSignal_WhenFrameNumberNotMeet()));
|
||||||
connect(m_Imager, SIGNAL(SpectralSignal(int)), this, SLOT(PlotSpectral(int)));
|
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)
|
||||||
{
|
{
|
||||||
//ʹ<>û<EFBFBD>е<EFBFBD>۲ɼ<DBB2>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹͣ<CDA3>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><CBB2><EFBFBD>ֿ<EFBFBD>ʼ<EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ᵼ<EFBFBD><E1B5BC><EFBFBD>ϴβɼ<CEB2><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>źŵ<C5BA><C5B5>ô˲ۺ<CBB2><DBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
//ʹ<>û<EFBFBD>е<EFBFBD>۲ɼ<DBB2>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹͣ<CDA3>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><CBB2><EFBFBD>ֿ<EFBFBD>ʼ<EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ᵼ<EFBFBD><E1B5BC><EFBFBD>ϴβɼ<CEB2><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>źŵ<C5BA><C5B5>ô˲ۺ<CBB2><DBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
QAction* checked = moveplatformActionGroup->checkedAction();
|
QAction* checked = moveplatformActionGroup->checkedAction();
|
||||||
QString checkedName = checked->objectName();
|
QString checkedName = checked->objectName();
|
||||||
if (number == -1 && checkedName == "mAction_RobotArm")
|
if (frameNumber == -1 && checkedName == "mAction_RobotArm")
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return;
|
//return;
|
||||||
//<2F><>ȡ<EFBFBD><C8A1>ͼ<EFBFBD>ؼ<EFBFBD>
|
//<2F><>ȡ<EFBFBD><C8A1>ͼ<EFBFBD>ؼ<EFBFBD>
|
||||||
QWidget* currentWidget = ui.ImageViewerTabWidget->widget(m_numberOfRecording);
|
QWidget* currentWidget = ui.ImageViewerTabWidget->widget(fileNumber);
|
||||||
QList<ImageViewer *> currentImageViewer = currentWidget->findChildren<ImageViewer *>();
|
QList<ImageViewer *> currentImageViewer = currentWidget->findChildren<ImageViewer *>();
|
||||||
currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>Ѿ<EFBFBD><D1BE>ɼ<EFBFBD><C9BC><EFBFBD>֡<EFBFBD><D6A1>
|
currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD>Ѿ<EFBFBD><D1BE>ɼ<EFBFBD><C9BC><EFBFBD>֡<EFBFBD><D6A1>
|
||||||
|
|
||||||
@ -2333,6 +2384,10 @@ void HPPA::onRecordFinishedSignal_WhenFrameNumberNotMeet()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkedName == "mAction_2AxisMotor_new")//<2F><><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD>ɼ<EFBFBD><C9BC>ߣ<EFBFBD><DFA3>м<EFBFBD><D0BC><EFBFBD>ij<EFBFBD><C4B3><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɺ<C9BA><F3B2BBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "ֹͣ<EFBFBD>ɼ<EFBFBD>ԭ<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>֡<EFBFBD><EFBFBD>û<EFBFBD>вɼ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ﵽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD>ֹͣ<EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD>" << std::endl;
|
std::cout << "ֹͣ<EFBFBD>ɼ<EFBFBD>ԭ<EFBFBD><EFBFBD>1<EFBFBD><EFBFBD>֡<EFBFBD><EFBFBD>û<EFBFBD>вɼ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ﵽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD>ֹͣ<EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD>" << std::endl;
|
||||||
|
|
||||||
@ -2342,6 +2397,14 @@ void HPPA::onRecordFinishedSignal_WhenFrameNumberNotMeet()
|
|||||||
m_RecordState++;
|
m_RecordState++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HPPA::onsequenceComplete()
|
||||||
|
{
|
||||||
|
ui.action_start_recording->setText(QString::fromLocal8Bit("<EFBFBD>ɼ<EFBFBD>"));
|
||||||
|
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(0,255,0);}");
|
||||||
|
|
||||||
|
m_RecordState++;
|
||||||
|
}
|
||||||
|
|
||||||
ForLoopControl::ForLoopControl()
|
ForLoopControl::ForLoopControl()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "PathPlan.h"
|
#include "PathPlan.h"
|
||||||
#include "RobotArmControl.h"
|
#include "RobotArmControl.h"
|
||||||
#include "OneMotorControl.h"
|
#include "OneMotorControl.h"
|
||||||
|
#include "TwoMotorControl.h"
|
||||||
|
|
||||||
#include "hppaConfigFile.h"
|
#include "hppaConfigFile.h"
|
||||||
#include "path_tc.h"
|
#include "path_tc.h"
|
||||||
@ -249,16 +250,20 @@ private:
|
|||||||
OneMotorControl* omc;
|
OneMotorControl* omc;
|
||||||
QDockWidget* dock_omc;
|
QDockWidget* dock_omc;
|
||||||
|
|
||||||
|
TwoMotorControl* tmc;
|
||||||
|
QDockWidget* dock_tmc;
|
||||||
|
|
||||||
|
|
||||||
PathPlan* m_pathPlan;
|
PathPlan* m_pathPlan;
|
||||||
|
|
||||||
FILE* m_hTimesFile;
|
FILE* m_hTimesFile;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void onPlotHyperspectralImageRgbImage(int number);
|
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber);
|
||||||
void PlotSpectral(int state);
|
void PlotSpectral(int state);
|
||||||
void onRecordFinishedSignal_WhenFrameNumberMeet();
|
void onRecordFinishedSignal_WhenFrameNumberMeet();
|
||||||
void onRecordFinishedSignal_WhenFrameNumberNotMeet();
|
void onRecordFinishedSignal_WhenFrameNumberNotMeet();
|
||||||
|
void onsequenceComplete();
|
||||||
|
|
||||||
void onExit();
|
void onExit();
|
||||||
void onconnect();//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
void onconnect();//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
149
HPPA/HPPA.ui
149
HPPA/HPPA.ui
@ -88,6 +88,11 @@
|
|||||||
<height>30</height>
|
<height>30</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>-1</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">QMenuBar{
|
<string notr="true">QMenuBar{
|
||||||
background:#F0F0F0;
|
background:#F0F0F0;
|
||||||
@ -123,6 +128,10 @@ color:white;
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>文件</string>
|
<string>文件</string>
|
||||||
</property>
|
</property>
|
||||||
|
<addaction name="action_9"/>
|
||||||
|
<addaction name="action_10"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="action_11"/>
|
||||||
<addaction name="action_exit"/>
|
<addaction name="action_exit"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuspectrometer">
|
<widget class="QMenu" name="menuspectrometer">
|
||||||
@ -130,6 +139,11 @@ color:white;
|
|||||||
<string>光谱仪</string>
|
<string>光谱仪</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menu">
|
<widget class="QMenu" name="menu">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>宋体</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>选择相机类型</string>
|
<string>选择相机类型</string>
|
||||||
</property>
|
</property>
|
||||||
@ -169,11 +183,33 @@ color:white;
|
|||||||
<addaction name="mAction_is_no_motor"/>
|
<addaction name="mAction_is_no_motor"/>
|
||||||
<addaction name="mAction_1AxisMotor"/>
|
<addaction name="mAction_1AxisMotor"/>
|
||||||
<addaction name="mAction_2AxisMotor"/>
|
<addaction name="mAction_2AxisMotor"/>
|
||||||
|
<addaction name="mAction_2AxisMotor_new"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="mAction_RobotArm"/>
|
<addaction name="mAction_RobotArm"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="mMenuScenario">
|
||||||
|
<property name="title">
|
||||||
|
<string>应用场景</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="mActionOneMotorScenario"/>
|
||||||
|
<addaction name="action_8"/>
|
||||||
|
<addaction name="action2"/>
|
||||||
|
<addaction name="action_7"/>
|
||||||
|
<addaction name="action_3"/>
|
||||||
|
<addaction name="action_6"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menu_4">
|
||||||
|
<property name="title">
|
||||||
|
<string>数据处理</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="action_4"/>
|
||||||
|
<addaction name="action_5"/>
|
||||||
|
<addaction name="action_13"/>
|
||||||
|
</widget>
|
||||||
<addaction name="file"/>
|
<addaction name="file"/>
|
||||||
<addaction name="menuspectrometer"/>
|
<addaction name="menuspectrometer"/>
|
||||||
|
<addaction name="mMenuScenario"/>
|
||||||
|
<addaction name="menu_4"/>
|
||||||
<addaction name="menu_2"/>
|
<addaction name="menu_2"/>
|
||||||
<addaction name="mWindowsMenu"/>
|
<addaction name="mWindowsMenu"/>
|
||||||
<addaction name="menuhelp"/>
|
<addaction name="menuhelp"/>
|
||||||
@ -185,6 +221,12 @@ color:white;
|
|||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>宋体</family>
|
||||||
|
<pointsize>2</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>相机控制</string>
|
<string>相机控制</string>
|
||||||
</property>
|
</property>
|
||||||
@ -301,13 +343,6 @@ QGroupBox:title {
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QPushButton" name="open_rgb_camera_btn">
|
|
||||||
<property name="text">
|
|
||||||
<string>打开</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QPushButton" name="close_rgb_camera_btn">
|
<widget class="QPushButton" name="close_rgb_camera_btn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -315,6 +350,13 @@ QGroupBox:title {
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QPushButton" name="open_rgb_camera_btn">
|
||||||
|
<property name="text">
|
||||||
|
<string>打开</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QLabel" name="cam_label">
|
<widget class="QLabel" name="cam_label">
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
@ -1450,6 +1492,11 @@ QDockWidget::title {
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>退出</string>
|
<string>退出</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Adobe Devanagari</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_open">
|
<action name="action_open">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -1493,6 +1540,11 @@ QDockWidget::title {
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>连接相机</string>
|
<string>连接相机</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>宋体</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionOpenDirectory">
|
<action name="actionOpenDirectory">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -1506,6 +1558,11 @@ QDockWidget::title {
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Pika L</string>
|
<string>Pika L</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>宋体</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="mActionCorning_410">
|
<action name="mActionCorning_410">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
@ -1522,6 +1579,11 @@ QDockWidget::title {
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Pika XC2</string>
|
<string>Pika XC2</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>宋体</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_about">
|
<action name="action_about">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -1535,6 +1597,11 @@ QDockWidget::title {
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Pika NIR</string>
|
<string>Pika NIR</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>宋体</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionpanel">
|
<action name="actionpanel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -1595,6 +1662,74 @@ QDockWidget::title {
|
|||||||
<string>1 轴线性马达</string>
|
<string>1 轴线性马达</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="mActionOneMotorScenario">
|
||||||
|
<property name="text">
|
||||||
|
<string>室内1轴线性平台</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>辐亮度</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>反射率</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>机械臂</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>显微镜</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>三脚架(旋转平台)</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>打开影像</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>关闭影像</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>设置</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>拼接</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>植物表型</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action2">
|
||||||
|
<property name="text">
|
||||||
|
<string>2轴旋转平台</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="mAction_2AxisMotor_new">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>2 轴线性马达_new</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
@ -6,7 +6,7 @@ ImagerOperationBase::ImagerOperationBase()
|
|||||||
m_bRecordControlState = true;
|
m_bRecordControlState = true;
|
||||||
|
|
||||||
m_FileName2Save = "tmp_image";
|
m_FileName2Save = "tmp_image";
|
||||||
m_FileSavedCounter = 1;
|
m_FileSavedCounter = 0;
|
||||||
|
|
||||||
m_RgbImage = new CImage();
|
m_RgbImage = new CImage();
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ void ImagerOperationBase::start_record()
|
|||||||
//ÿ<><C3BF>1s<31><73><EFBFBD><EFBFBD>һ<EFBFBD>ν<EFBFBD><CEBD><EFBFBD>ͼ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>
|
//ÿ<><C3BF>1s<31><73><EFBFBD><EFBFBD>һ<EFBFBD>ν<EFBFBD><CEBD><EFBFBD>ͼ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>
|
||||||
if (m_iFrameCounter % (int)getFramerate() == 0)
|
if (m_iFrameCounter % (int)getFramerate() == 0)
|
||||||
{
|
{
|
||||||
emit PlotSignal(m_iFrameCounter);
|
emit PlotSignal(m_FileSavedCounter, m_iFrameCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_iFrameCounter >= m_iFrameNumber)
|
if (m_iFrameCounter >= m_iFrameNumber)
|
||||||
@ -310,14 +310,14 @@ void ImagerOperationBase::start_record()
|
|||||||
}
|
}
|
||||||
imagerStopCollect();
|
imagerStopCollect();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼǰ<CDBC><C7B0>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
//m_RgbImage
|
||||||
|
emit PlotSignal(m_FileSavedCounter, -1);//<2F><>1<EFBFBD><31><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>Է<EFBFBD><D4B7>ɼ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD>ʵı<CAB5><C4B1><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>ȫ<EFBFBD><C8AB>2<EFBFBD><32>ʹ<EFBFBD>û<EFBFBD>е<EFBFBD>۲ɼ<DBB2>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹͣ<CDA3>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD>俪ʼ<E4BFAA>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ᵼ<EFBFBD><E1B5BC><EFBFBD>ϴβɼ<CEB2><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>źŵ<C5BA><C5B5>õIJۺ<C4B2><DBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>˼<EFBFBD><CBBC>ݣ<EFBFBD>ע<EFBFBD>͵<EFBFBD>
|
||||||
|
|
||||||
m_bRecordControlState = false;
|
m_bRecordControlState = false;
|
||||||
WriteHdr();
|
WriteHdr();
|
||||||
m_FileSavedCounter++;
|
m_FileSavedCounter++;
|
||||||
|
|
||||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼǰ<CDBC><C7B0>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
//m_RgbImage
|
|
||||||
emit PlotSignal(-1);//<2F><>1<EFBFBD><31><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>Է<EFBFBD><D4B7>ɼ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD>ʵı<CAB5><C4B1><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>ȫ<EFBFBD><C8AB>2<EFBFBD><32>ʹ<EFBFBD>û<EFBFBD>е<EFBFBD>۲ɼ<DBB2>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹͣ<CDA3>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD>俪ʼ<E4BFAA>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ᵼ<EFBFBD><E1B5BC><EFBFBD>ϴβɼ<CEB2><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4>źŵ<C5BA><C5B5>õIJۺ<C4B2><DBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>˼<EFBFBD><CBBC>ݣ<EFBFBD>ע<EFBFBD>͵<EFBFBD>
|
|
||||||
|
|
||||||
if (m_iFrameCounter >= m_iFrameNumber)
|
if (m_iFrameCounter >= m_iFrameNumber)
|
||||||
{
|
{
|
||||||
emit RecordFinishedSignal_WhenFrameNumberMeet();
|
emit RecordFinishedSignal_WhenFrameNumberMeet();
|
||||||
@ -341,7 +341,7 @@ void ImagerOperationBase::setFrameNumber(int FrameNumber)
|
|||||||
void ImagerOperationBase::setFileName2Save(string FileName)
|
void ImagerOperationBase::setFileName2Save(string FileName)
|
||||||
{
|
{
|
||||||
m_FileName2Save = FileName;
|
m_FileName2Save = FileName;
|
||||||
m_FileSavedCounter = 1;
|
m_FileSavedCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImagerOperationBase::setFocusControlState(bool FocusControlState)
|
void ImagerOperationBase::setFocusControlState(bool FocusControlState)
|
||||||
@ -449,6 +449,11 @@ void ImagerOperationBase::setRecordControlState(bool RecordControlState)
|
|||||||
m_bRecordControlState = RecordControlState;
|
m_bRecordControlState = RecordControlState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImagerOperationBase::stop_record()
|
||||||
|
{
|
||||||
|
m_bRecordControlState = false;
|
||||||
|
}
|
||||||
|
|
||||||
int ImagerOperationBase::getFrameCounter() const
|
int ImagerOperationBase::getFrameCounter() const
|
||||||
{
|
{
|
||||||
return m_iFrameCounter;
|
return m_iFrameCounter;
|
||||||
|
@ -94,12 +94,13 @@ public slots:
|
|||||||
virtual double auto_exposure();
|
virtual double auto_exposure();
|
||||||
virtual void focus();
|
virtual void focus();
|
||||||
virtual void start_record();
|
virtual void start_record();
|
||||||
|
void stop_record();
|
||||||
virtual void record_dark();
|
virtual void record_dark();
|
||||||
virtual void record_white();
|
virtual void record_white();
|
||||||
|
|
||||||
void getFocusIndexSobel();
|
void getFocusIndexSobel();
|
||||||
signals:
|
signals:
|
||||||
void PlotSignal(int);//<2F><><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>źţ<C5BA>-1<EFBFBD><EFBFBD><EFBFBD>˴βɼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD>
|
void PlotSignal(int, int);//<2F><><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>źţ<C5BA><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڼ<EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><EFBFBD><EFBFBD><EFBFBD>-1<><31><EFBFBD><EFBFBD><EFBFBD>˴βɼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
void RecordFinishedSignal_WhenFrameNumberMeet();//<2F>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>źţ<C5BA><C5A3><EFBFBD>Ҫ<EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>m_iFrameNumber<65><72><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>
|
void RecordFinishedSignal_WhenFrameNumberMeet();//<2F>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>źţ<C5BA><C5A3><EFBFBD>Ҫ<EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>m_iFrameNumber<65><72><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>
|
||||||
void RecordFinishedSignal_WhenFrameNumberNotMeet();//<2F>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>źţ<C5BA><C5A3><EFBFBD>Ҫ<EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>m_iFrameNumber<65><72>û<EFBFBD>вɼ<D0B2><C9BC><EFBFBD><EFBFBD>ɣ<EFBFBD><C9A3><EFBFBD>;ֹͣ<CDA3>ɼ<EFBFBD>
|
void RecordFinishedSignal_WhenFrameNumberNotMeet();//<2F>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>źţ<C5BA><C5A3><EFBFBD>Ҫ<EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>m_iFrameNumber<65><72>û<EFBFBD>вɼ<D0B2><C9BC><EFBFBD><EFBFBD>ɣ<EFBFBD><C9A3><EFBFBD>;ֹͣ<CDA3>ɼ<EFBFBD>
|
||||||
void SpectralSignal(int);//<2F><><EFBFBD><EFBFBD>1<EFBFBD><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƹ<EFBFBD><C6B9>ף<EFBFBD><D7A3><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><30>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɣ<EFBFBD>
|
void SpectralSignal(int);//<2F><><EFBFBD><EFBFBD>1<EFBFBD><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƹ<EFBFBD><C6B9>ף<EFBFBD><D7A3><EFBFBD><EFBFBD><EFBFBD>0<EFBFBD><30>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɣ<EFBFBD>
|
||||||
|
@ -353,7 +353,7 @@ void ResononNirImager::start_record()
|
|||||||
//ÿ<><C3BF>1s<31><73><EFBFBD><EFBFBD>һ<EFBFBD>ν<EFBFBD><CEBD><EFBFBD>ͼ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>
|
//ÿ<><C3BF>1s<31><73><EFBFBD><EFBFBD>һ<EFBFBD>ν<EFBFBD><CEBD><EFBFBD>ͼ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>
|
||||||
if (m_iFrameCounter % (int)getFramerate() == 0)
|
if (m_iFrameCounter % (int)getFramerate() == 0)
|
||||||
{
|
{
|
||||||
emit PlotSignal(m_iFrameCounter);
|
emit PlotSignal(m_FileSavedCounter, m_iFrameCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_iFrameCounter >= m_iFrameNumber)
|
if (m_iFrameCounter >= m_iFrameNumber)
|
||||||
@ -365,14 +365,14 @@ void ResononNirImager::start_record()
|
|||||||
}
|
}
|
||||||
imagerStopCollect();
|
imagerStopCollect();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼǰ<CDBC><C7B0>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
//m_RgbImage
|
||||||
|
emit PlotSignal(m_FileSavedCounter, -1);//<2F>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>Է<EFBFBD><D4B7>ɼ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD>ʵı<CAB5><C4B1><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>ȫ
|
||||||
|
|
||||||
m_bRecordControlState = false;
|
m_bRecordControlState = false;
|
||||||
WriteHdr();
|
WriteHdr();
|
||||||
m_FileSavedCounter++;
|
m_FileSavedCounter++;
|
||||||
|
|
||||||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼǰ<CDBC><C7B0>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
//m_RgbImage
|
|
||||||
emit PlotSignal(-1);//<2F>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD>ɺ<EFBFBD><C9BA><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD>Է<EFBFBD><D4B7>ɼ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD>ʵı<CAB5><C4B1><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC>ȫ
|
|
||||||
|
|
||||||
if (m_iFrameCounter >= m_iFrameNumber)
|
if (m_iFrameCounter >= m_iFrameNumber)
|
||||||
{
|
{
|
||||||
emit RecordFinishedSignal_WhenFrameNumberMeet();
|
emit RecordFinishedSignal_WhenFrameNumberMeet();
|
||||||
|
581
HPPA/TwoMotorControl.cpp
Normal file
581
HPPA/TwoMotorControl.cpp
Normal file
@ -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<PathLine>>("QVector<PathLine>");
|
||||||
|
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<PathLine>)), m_coordinator, SLOT(start(QVector<PathLine>)));
|
||||||
|
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<PathLine> 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<double>)), this, SLOT(displayRealTimeLoc(std::vector<double>)));
|
||||||
|
|
||||||
|
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<int>)), this, SLOT(display_motors_connectivity(std::vector<int>)));
|
||||||
|
|
||||||
|
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<int> connectivity)
|
||||||
|
{
|
||||||
|
//std::cout << "-----------------------------------"<<connectivity.size()<< std::endl;
|
||||||
|
if (connectivity[0])
|
||||||
|
{
|
||||||
|
this->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<double> 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("读取成功!"));
|
||||||
|
}
|
89
HPPA/TwoMotorControl.h
Normal file
89
HPPA/TwoMotorControl.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
#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<double> loc);
|
||||||
|
void display_motors_connectivity(std::vector<int> 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<double>, const std::vector<double>, int);
|
||||||
|
void stopSignal(int);
|
||||||
|
|
||||||
|
void rangeMeasurement(int, double, int);
|
||||||
|
void zeroStartSignal(int);
|
||||||
|
void testConnectivitySignal(int, int);
|
||||||
|
|
||||||
|
void start(QVector<PathLine>);
|
||||||
|
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;
|
||||||
|
};
|
1010
HPPA/twoMotorControl.ui
Normal file
1010
HPPA/twoMotorControl.ui
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user