2026-01-22 12:57:54 +08:00
|
|
|
|
#ifndef BAGTHREADPOSITIONPRESENTER_H
|
|
|
|
|
|
#define BAGTHREADPOSITIONPRESENTER_H
|
|
|
|
|
|
|
|
|
|
|
|
#include <condition_variable>
|
|
|
|
|
|
#include <thread>
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
|
|
|
|
#include "BasePresenter.h"
|
|
|
|
|
|
#include "IVrEyeDevice.h"
|
|
|
|
|
|
#include "ConfigManager.h"
|
2026-01-27 20:43:12 +08:00
|
|
|
|
#include "IVrConfig.h"
|
2026-01-22 12:57:54 +08:00
|
|
|
|
#include "IYBagThreadPositionStatus.h"
|
|
|
|
|
|
#include "SG_baseDataType.h"
|
|
|
|
|
|
#include "VrConvert.h"
|
|
|
|
|
|
#include "LaserDataLoader.h"
|
|
|
|
|
|
#include "CommonDialogCameraLevel.h" // 引入通用对话框的接口
|
2026-02-11 00:53:51 +08:00
|
|
|
|
#include "IYModbusTCPClient.h" // ModbusTCP客户端接口
|
2026-01-22 12:57:54 +08:00
|
|
|
|
#include <QImage>
|
|
|
|
|
|
#include <QPainter>
|
|
|
|
|
|
#include <QColor>
|
|
|
|
|
|
#include <QObject>
|
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
|
|
|
|
// Forward declarations
|
|
|
|
|
|
class DetectPresenter;
|
|
|
|
|
|
|
|
|
|
|
|
class BagThreadPositionPresenter : public BasePresenter, public IVrConfigChangeNotify,
|
|
|
|
|
|
public ICameraLevelCalculator, public ICameraLevelResultSaver
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
explicit BagThreadPositionPresenter(QObject *parent = nullptr);
|
|
|
|
|
|
~BagThreadPositionPresenter();
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
|
int InitApp() override;
|
|
|
|
|
|
|
|
|
|
|
|
// 反初始化
|
|
|
|
|
|
void DeinitApp();
|
|
|
|
|
|
|
|
|
|
|
|
// 触发检测
|
|
|
|
|
|
bool TriggerDetection(int cameraIndex = -1);
|
|
|
|
|
|
|
|
|
|
|
|
// 加载文件并检测
|
|
|
|
|
|
int LoadAndDetect(const QString& fileName);
|
|
|
|
|
|
|
|
|
|
|
|
// 重连相机
|
|
|
|
|
|
void ReconnectCamera();
|
|
|
|
|
|
|
|
|
|
|
|
// 获取/设置算法参数
|
|
|
|
|
|
struct AlgoParams {
|
|
|
|
|
|
VrThreadParam threadParam;
|
|
|
|
|
|
VrCornerParam cornerParam;
|
|
|
|
|
|
VrOutlierFilterParam filterParam;
|
|
|
|
|
|
VrTreeGrowParam growParam;
|
|
|
|
|
|
};
|
|
|
|
|
|
AlgoParams GetAlgoParams() const;
|
|
|
|
|
|
void SetAlgoParams(const AlgoParams& params);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取配置管理器
|
|
|
|
|
|
ConfigManager* GetConfigManager() { return m_pConfigManager; }
|
|
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 应用基准距离到指定相机设备
|
|
|
|
|
|
void ApplyBaseDistance(int cameraIndex, double baseDistance);
|
|
|
|
|
|
|
|
|
|
|
|
// 应用ModbusTCP配置(IP和大小端)
|
|
|
|
|
|
void ApplyModbusConfig(const std::string& ip, bool bigEndian);
|
|
|
|
|
|
|
2026-01-22 12:57:54 +08:00
|
|
|
|
// 手眼标定矩阵管理
|
|
|
|
|
|
CalibMatrix GetClibMatrix(int index) const;
|
|
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 面标定辅助函数
|
|
|
|
|
|
SSG_planeCalibPara GetBaseCalibPara(const std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& scanData);
|
|
|
|
|
|
|
2026-01-22 12:57:54 +08:00
|
|
|
|
// 实现IVrConfigChangeNotify接口
|
|
|
|
|
|
virtual void OnConfigChanged(const ConfigResult& configResult) override;
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 实现 ICameraLevelCalculator 接口 ============
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 计算平面调平参数
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool CalculatePlaneCalibration(
|
|
|
|
|
|
const std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& scanData,
|
|
|
|
|
|
double planeCalib[9],
|
|
|
|
|
|
double& planeHeight,
|
|
|
|
|
|
double invRMatrix[9]) override;
|
|
|
|
|
|
|
|
|
|
|
|
// ============ 实现 ICameraLevelResultSaver 接口 ============
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 保存相机调平结果到配置文件
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool SaveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
|
|
|
|
|
|
int cameraIndex, const QString& cameraName) override;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 从配置文件加载相机调平结果
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool LoadLevelingResults(int cameraIndex, const QString& cameraName,
|
|
|
|
|
|
double planeCalib[9], double& planeHeight, double invRMatrix[9]) override;
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
// ============ 实现 BasePresenter 纯虚函数 ============
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 初始化算法参数(实现纯虚函数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
int InitAlgoParams() override;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 执行算法检测(实现纯虚函数)
|
|
|
|
|
|
* @param detectionDataCache 检测数据缓存的引用
|
|
|
|
|
|
*/
|
|
|
|
|
|
int ProcessAlgoDetection(std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& detectionDataCache) override;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 获取检测数据类型(实现纯虚函数)
|
|
|
|
|
|
* 包裹拆线位置定位项目只使用Position点云数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
EVzResultDataType GetDetectionDataType() override {
|
|
|
|
|
|
return keResultDataType_Position;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 相机状态变化通知(实现纯虚函数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnCameraStatusChanged(int cameraIndex, bool isConnected) override;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 工作状态变化通知(重写虚函数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnWorkStatusChanged(WorkStatus status) override;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 相机数量变化通知(重写虚函数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnCameraCountChanged(int count) override;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 状态文字更新通知(重写虚函数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnStatusUpdate(const std::string& statusMessage) override;
|
|
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief ModbusTCP连接状态变化通知(重写虚函数)
|
|
|
|
|
|
*/
|
|
|
|
|
|
void OnModbusServerStatusChanged(bool isConnected) override;
|
|
|
|
|
|
|
2026-01-27 20:43:12 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 创建设备对象(重写虚函数)
|
|
|
|
|
|
* BagThreadPosition项目使用GlLineLaserDevice
|
|
|
|
|
|
*/
|
|
|
|
|
|
int CreateDevice(IVrEyeDevice** ppDevice) override;
|
|
|
|
|
|
|
2026-02-07 23:46:44 +08:00
|
|
|
|
/**
|
2026-02-11 00:53:51 +08:00
|
|
|
|
* @brief 跳过BasePresenter的ModbusTCP Server启动
|
|
|
|
|
|
* BagThreadPosition使用Client模式主动连接PLC
|
2026-02-07 23:46:44 +08:00
|
|
|
|
*/
|
2026-02-11 00:53:51 +08:00
|
|
|
|
bool ShouldStartModbusServer() const override { return false; }
|
2026-02-07 23:46:44 +08:00
|
|
|
|
|
2026-01-22 12:57:54 +08:00
|
|
|
|
private:
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 连接状态检查和更新
|
|
|
|
|
|
void CheckAndUpdateWorkStatus();
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 根据相机索引获取调平参数
|
|
|
|
|
|
SSG_planeCalibPara _GetCameraCalibParam(int cameraIndex);
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 发送检测结果到ModbusTCP寄存器
|
|
|
|
|
|
void _SendDetectionResultToModbus(const DetectionResult& detectionResult);
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// Float转寄存器(支持大小端切换)
|
|
|
|
|
|
void _FloatToRegisters(float value, uint16_t* regs, bool bigEndian);
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// ============ ModbusTCP Client 方法 ============
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 初始化ModbusTCP客户端
|
|
|
|
|
|
void InitModbusClient(const std::string& ip, uint16_t port, int pollingInterval);
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
2026-02-11 00:53:51 +08:00
|
|
|
|
// 关闭ModbusTCP客户端
|
|
|
|
|
|
void ShutdownModbusClient();
|
|
|
|
|
|
|
|
|
|
|
|
// 启动轮询线程
|
|
|
|
|
|
void StartModbusPolling();
|
|
|
|
|
|
|
|
|
|
|
|
// 停止轮询线程
|
|
|
|
|
|
void StopModbusPolling();
|
|
|
|
|
|
|
|
|
|
|
|
// 轮询线程函数
|
|
|
|
|
|
void ModbusPollingThreadFunc();
|
|
|
|
|
|
|
|
|
|
|
|
// 检查连接状态
|
|
|
|
|
|
bool CheckModbusConnection();
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试连接
|
|
|
|
|
|
bool TryConnectModbus();
|
|
|
|
|
|
|
|
|
|
|
|
// 读取扫描请求寄存器
|
|
|
|
|
|
int ReadScanRequest();
|
|
|
|
|
|
|
|
|
|
|
|
// 写入远端PLC多个寄存器
|
|
|
|
|
|
bool WriteRemoteRegisters(uint16_t startAddress, const std::vector<uint16_t>& values);
|
|
|
|
|
|
|
|
|
|
|
|
// 写入远端PLC单个寄存器
|
|
|
|
|
|
bool WriteRemoteSingleRegister(uint16_t address, uint16_t value);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查ModbusTCP客户端是否已连接
|
|
|
|
|
|
bool IsModbusClientConnected() const;
|
2026-01-22 12:57:54 +08:00
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
// BagThreadPositionPresenter 特有的成员变量
|
|
|
|
|
|
ConfigManager* m_pConfigManager = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// 检测处理器
|
|
|
|
|
|
DetectPresenter* m_pDetectPresenter = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// 手眼标定矩阵列表(从独立文件加载,暂时保留在Presenter中)
|
|
|
|
|
|
std::vector<CalibMatrix> m_clibMatrixList;
|
2026-02-07 23:46:44 +08:00
|
|
|
|
|
|
|
|
|
|
// ModbusTCP协议相关
|
|
|
|
|
|
DetectionResult m_lastDetectionResult; // 最新的检测结果
|
|
|
|
|
|
std::mutex m_modbusResultMutex; // 保护检测结果的互斥锁
|
2026-02-11 00:53:51 +08:00
|
|
|
|
bool m_modbusBigEndian = true; // ModbusTCP大小端配置
|
|
|
|
|
|
|
|
|
|
|
|
// ============ ModbusTCP Client 成员 ============
|
|
|
|
|
|
IYModbusTCPClient* m_modbusClient = nullptr; // Modbus客户端实例
|
|
|
|
|
|
std::string m_modbusClientIP; // 远端PLC IP
|
|
|
|
|
|
uint16_t m_modbusClientPort = 502; // 远端PLC端口
|
|
|
|
|
|
int m_modbusPollingInterval = 200; // 轮询间隔(毫秒)
|
|
|
|
|
|
|
|
|
|
|
|
std::thread m_modbusPollingThread; // 轮询线程
|
|
|
|
|
|
std::atomic<bool> m_modbusPollingRunning{false}; // 轮询线程运行标志
|
|
|
|
|
|
std::atomic<bool> m_modbusPollingPaused{false}; // 轮询暂停标志(检测期间暂停)
|
|
|
|
|
|
std::atomic<bool> m_modbusShutdownRequested{false}; // 关闭请求标志
|
|
|
|
|
|
|
|
|
|
|
|
mutable std::mutex m_modbusClientMutex; // 保护 m_modbusClient
|
|
|
|
|
|
bool m_lastScanRequestState = false; // 上次扫描请求状态(边沿检测)
|
|
|
|
|
|
bool m_lastModbusConnectedState = false; // 上次连接状态
|
|
|
|
|
|
int m_modbusReconnectAttempts = 0; // 重连次数
|
|
|
|
|
|
int m_modbusReadFailCount = 0; // 连续读取失败次数
|
|
|
|
|
|
static constexpr int MAX_READ_FAIL_COUNT = 3; // 最大连续失败次数,超过则断开重连
|
2026-01-22 12:57:54 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // BAGTHREADPOSITIONPRESENTER_H
|