撕裂代码出版提交

This commit is contained in:
yiyi 2025-09-18 23:49:32 +08:00
parent 032a0c017d
commit 9e3ba0b8c9
42 changed files with 1313 additions and 312 deletions

View File

@ -14,8 +14,7 @@ win32-msvc {
INCLUDEPATH += $$PWD/Presenter/Inc
INCLUDEPATH += ../BeltTearingConfig/Inc
INCLUDEPATH += ../../../VrNets/tcpClient/Inc
INCLUDEPATH += ../../../VrNets/TCPClient/Inc
INCLUDEPATH += ../../../VrUtils/Inc
# Link libraries

View File

@ -2,9 +2,10 @@
#define BELTTEARINGPRESENTER_H
#include "IVrBeltTearingConfig.h"
#include "VrTcpClient.h"
#include "IVrTCPClient.h"
#include <QObject>
#include <QString>
#include <QTimer>
#include "widgets/DeviceStatusWidget.h"
enum class ByteDataType {
@ -22,7 +23,7 @@ public:
explicit BeltTearingPresenter(QWidget* parent = nullptr);
~BeltTearingPresenter();
void Init();
void Init(); // 状态更新接口
QStringList getServerNames() const;
QString getServerIp(const QString &serverName) const ;
@ -49,13 +50,25 @@ private slots:
void onDisconnected(const QString &serverName);
void onDataReceived(const QString &serverName, const QByteArray &data);
void onTcpError(const QString &serverName, const QString &error);
void onReconnectTimer();
private:
IStatusUpdate* m_statusUpdate = nullptr; // 状态更新接口
IVrBeltTearingConfig * m_config = nullptr; // 配置接口
DeviceStatusWidget* m_deviceStatusWidget = nullptr; // 设备状态控件
QMap<QString, VrTcpClient*> m_tcpClients; // 服务器名称 -> TCP客户端映射
QMap<QString, ServerInfo> m_serverInfos; // 服务器名称 -> 服务器信息映射
private:
// 静态回调函数用于C接口- 已弃用使用lambda替代
// static void tcpDataReceivedCallback(const char* pData, const int nLen);
// static void tcpLinkStatusCallback(bool connected);
// 实例方法
void handleTcpDataReceived(const QString &serverName, const char* pData, const int nLen);
void handleTcpLinkStatus(const QString &serverName, bool connected);
private:
IVrBeltTearingConfig * m_config = nullptr; // 配置接口
IStatusUpdate* m_statusUpdate = nullptr; // 状态更新接口
DeviceStatusWidget* m_deviceStatusWidget = nullptr; // 设备状态控件
QMap<QString, IVrTCPClient*> m_tcpClients; // 服务器名称 -> TCP客户端映射
QMap<QString, ServerInfo> m_serverInfos; // 服务器名称 -> 服务器信息映射
QMap<QString, QTimer*> m_reconnectTimers; // 重连定时器
QMap<QString, bool> m_connectionStatus; // 连接状态
};
#endif // BELTTEARINGPRESENTER_H

View File

@ -1,5 +1,5 @@
#include "BeltTearingPresenter.h"
#include "VrTcpClient.h"
#include "IVrTCPClient.h"
#include "PathManager.h"
#include "VrLog.h"
#include <QDebug>
@ -26,13 +26,19 @@ BeltTearingPresenter::BeltTearingPresenter(QWidget* parent)
BeltTearingPresenter::~BeltTearingPresenter()
{
disconnectFromServer();
// 删除所有TCP客户端
for (auto it = m_tcpClients.begin(); it != m_tcpClients.end(); ++it) {
delete it.value();
IVrTCPClient::DestroyInstance(it.value());
}
m_tcpClients.clear();
// 删除所有重连定时器
for (auto it = m_reconnectTimers.begin(); it != m_reconnectTimers.end(); ++it) {
delete it.value();
}
m_reconnectTimers.clear();
if (m_config) {
delete m_config;
m_config = nullptr;
@ -79,25 +85,19 @@ bool BeltTearingPresenter::initializeConfig(const QString &configPath)
// 存储所有启用的服务器信息
QList<DeviceInfo> devices;
QStringList deviceAliases;
for (const auto &server : servers) {
QString serverAliaseName = QString("%1_%2").arg(QString::fromStdString(server.name)).arg(CVrDateUtils::GetTimestamp());
m_serverInfos[serverAliaseName] = server;
bool bRet = connectToServer(server, serverAliaseName);
if(!bRet) continue;
// 添加到设备列表
devices.append(DeviceInfo(QString::fromStdString(server.name), serverAliaseName, QString::fromStdString(server.ip), DeviceStatus::Offline, true));
deviceAliases.append(serverAliaseName);
LOG_DEBUG("Server configured: %s %s:%d \n", serverAliaseName.toStdString().c_str(), server.ip.c_str(), server.port);
}
LOG_DEBUG("Init config finish. Found %d enabled servers \n", m_serverInfos.size());
// 收集设备别名列表
QStringList deviceAliases;
for (const auto &server : devices) {
deviceAliases.append(server.alias);
}
if(m_statusUpdate){
m_statusUpdate->OnNeedShowImageCount(deviceAliases);
@ -106,6 +106,11 @@ bool BeltTearingPresenter::initializeConfig(const QString &configPath)
if (m_deviceStatusWidget) {
m_deviceStatusWidget->setDevices(devices);
}
// 连接
for(size_t i = 0 ; i < devices.size() ; i++){
connectToServer(servers[i], deviceAliases[i]);
}
if (m_serverInfos.empty()) {
LOG_WARNING("No enabled servers found\n");
@ -122,38 +127,52 @@ bool BeltTearingPresenter::connectToServer(const ServerInfo &serverInfo, const Q
// 创建TCP客户端如果不存在
if (!m_tcpClients.contains(targetServerName)) {
VrTcpClient *client = new VrTcpClient();
IVrTCPClient *client = IVrTCPClient::CreateInstance();
if (!client) {
LOG_ERROR("Failed to create TCP client for %s", targetServerName.toStdString().c_str());
return false;
}
m_tcpClients[targetServerName] = client;
// 连接TCP客户端的信号到Presenter的槽函数
connect(client, &IVrTcpClient::connected, this, [this, targetServerName]() {
onConnected(targetServerName);
});
connect(client, &IVrTcpClient::disconnected, this, [this, targetServerName]() {
onDisconnected(targetServerName);
});
connect(client, &IVrTcpClient::connectionError, this, [this, targetServerName](const QString &error) {
onTcpError(targetServerName, error);
});
connect(client, &IVrTcpClient::dataReceived, this, [this, targetServerName](const QByteArray &data) {
onDataReceived(targetServerName, data);
});
m_connectionStatus[targetServerName] = false;
// 创建重连定时器
QTimer *reconnectTimer = new QTimer(this);
reconnectTimer->setSingleShot(true);
reconnectTimer->setInterval(5000); // 5秒重连间隔
connect(reconnectTimer, &QTimer::timeout, this, &BeltTearingPresenter::onReconnectTimer);
m_reconnectTimers[targetServerName] = reconnectTimer;
}
VrTcpClient *client = m_tcpClients[targetServerName];
// 设置自动重连
client->setAutoReconnect(true);
client->setReconnectInterval(5000); // 5秒重连间隔
IVrTCPClient *client = m_tcpClients[targetServerName];
// 连接服务器
bool success = client->connectToServer(QString::fromStdString(serverInfo.ip), serverInfo.port);
if (!success) {
LOG_ERROR("Failed to initiate connection to %s", targetServerName.toStdString().c_str());
int linkResult = client->LinkDevice(serverInfo.ip, serverInfo.port, true, // 启用自动重连
[this, targetServerName](IVrTCPClient* pClient, bool connected, void* pParam) {
this->handleTcpLinkStatus(targetServerName, connected);
}, this
);
LOG_DEBUG("connectToServer %s ret : %d \n", targetServerName.toStdString().c_str(), linkResult);
// 启动工作线程
int workResult = client->StartWork(
[this, targetServerName](IVrTCPClient* pClient, const char* pData, const int nLen, void* pParam) {
this->handleTcpDataReceived(targetServerName, pData, nLen);
}, this
);
if (workResult != 0) {
LOG_ERROR("Failed to start TCP client work thread for %s", targetServerName.toStdString().c_str());
return false;
}
return success;
if (linkResult != 0) {
LOG_ERROR("Failed to initiate connection to %s", targetServerName.toStdString().c_str());
return false;
}
return true;
}
void BeltTearingPresenter::disconnectFromServer(const QString &serverName)
@ -161,14 +180,24 @@ void BeltTearingPresenter::disconnectFromServer(const QString &serverName)
if (serverName.isEmpty()) {
// 断开所有连接
for (auto it = m_tcpClients.begin(); it != m_tcpClients.end(); ++it) {
if (it.value()->isConnected()) {
it.value()->disconnectFromServer();
}
it.value()->CloseDevice();
m_connectionStatus[it.key()] = false;
}
// 停止所有重连定时器
for (auto it = m_reconnectTimers.begin(); it != m_reconnectTimers.end(); ++it) {
it.value()->stop();
}
} else {
// 断开指定服务器连接
if (m_tcpClients.contains(serverName) && m_tcpClients[serverName]->isConnected()) {
m_tcpClients[serverName]->disconnectFromServer();
if (m_tcpClients.contains(serverName)) {
m_tcpClients[serverName]->CloseDevice();
m_connectionStatus[serverName] = false;
}
// 停止重连定时器
if (m_reconnectTimers.contains(serverName)) {
m_reconnectTimers[serverName]->stop();
}
}
}
@ -176,13 +205,13 @@ void BeltTearingPresenter::disconnectFromServer(const QString &serverName)
bool BeltTearingPresenter::isConnected(const QString &serverName) const
{
if(serverName.isEmpty()) return false;
QString targetServerName = serverName;
if (m_tcpClients.contains(targetServerName)) {
return m_tcpClients[targetServerName]->isConnected();
if (m_connectionStatus.contains(targetServerName)) {
return m_connectionStatus[targetServerName];
}
return false;
}
@ -190,27 +219,27 @@ bool BeltTearingPresenter::sendData(const QByteArray &data, const QString &serve
{
if(serverName.isEmpty()) return false;
QString targetServerName = serverName;
if (!isConnected(targetServerName)) {
LOG_ERROR("Not connected to server: %s", targetServerName.toStdString().c_str());
return false;
}
if (data.isEmpty()) {
LOG_ERROR("Empty data to send");
return false;
}
if (!m_tcpClients.contains(targetServerName)) {
LOG_ERROR("Server client not found: %s", targetServerName.toStdString().c_str());
return false;
return false;
}
bool success = m_tcpClients[targetServerName]->sendData(data);
bool success = m_tcpClients[targetServerName]->SendData(data.constData(), data.size());
if (!success) {
LOG_ERROR("Failed to send data to %s", targetServerName.toStdString().c_str());
}
return success;
}
@ -249,6 +278,13 @@ void BeltTearingPresenter::onConnected(const QString &serverName)
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateDeviceStatus(serverName, DeviceStatus::Online);
}
// 通知主界面TCP客户端连接成功
if (m_statusUpdate) {
m_statusUpdate->OnServerConnected(serverName);
m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Ready);
m_statusUpdate->OnStatusUpdate(QString("TCP客户端 %1 连接成功").arg(serverName));
}
}
void BeltTearingPresenter::onDisconnected(const QString &serverName)
@ -257,6 +293,13 @@ void BeltTearingPresenter::onDisconnected(const QString &serverName)
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateDeviceStatus(serverName, DeviceStatus::Offline);
}
// 通知主界面TCP客户端连接断开
if (m_statusUpdate) {
m_statusUpdate->OnServerDisconnected(serverName);
m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Disconnected);
m_statusUpdate->OnStatusUpdate(QString("TCP客户端 %1 连接断开").arg(serverName));
}
}
void BeltTearingPresenter::onDataReceived(const QString &serverName, const QByteArray &data)
@ -319,10 +362,67 @@ void BeltTearingPresenter::onDataReceived(const QString &serverName, const QByte
}
}
void BeltTearingPresenter::onTcpError(const QString &error, const QString &serverName)
void BeltTearingPresenter::onTcpError(const QString &serverName, const QString &error)
{
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateDeviceStatus(serverName, DeviceStatus::Error);
}
// 通知主界面TCP客户端发生错误
if (m_statusUpdate) {
m_statusUpdate->OnWorkStatusChanged(BeltTearingWorkStatus::Error);
m_statusUpdate->OnErrorOccurred(QString("TCP客户端 %1 错误: %2").arg(serverName, error));
}
}
void BeltTearingPresenter::onReconnectTimer()
{
QTimer *timer = qobject_cast<QTimer*>(sender());
if (!timer) return;
// 找到对应的服务器名称
QString serverName;
for (auto it = m_reconnectTimers.begin(); it != m_reconnectTimers.end(); ++it) {
if (it.value() == timer) {
serverName = it.key();
break;
}
}
if (serverName.isEmpty()) return;
// 如果当前没有连接,尝试重连
if (!isConnected(serverName) && m_serverInfos.contains(serverName)) {
const ServerInfo &serverInfo = m_serverInfos[serverName];
LOG_DEBUG("Attempting to reconnect to %s", serverName.toStdString().c_str());
connectToServer(serverInfo, serverName);
}
}
void BeltTearingPresenter::handleTcpDataReceived(const QString &serverName, const char* pData, const int nLen)
{
if (!pData || nLen <= 0) return;
QByteArray data(pData, nLen);
onDataReceived(serverName, data);
}
void BeltTearingPresenter::handleTcpLinkStatus(const QString &serverName, bool connected)
{
m_connectionStatus[serverName] = connected;
if (connected) {
// 停止重连定时器
if (m_reconnectTimers.contains(serverName)) {
m_reconnectTimers[serverName]->stop();
}
onConnected(serverName);
} else {
// 启动重连定时器
if (m_reconnectTimers.contains(serverName)) {
m_reconnectTimers[serverName]->start();
}
onDisconnected(serverName);
}
}

View File

@ -173,7 +173,7 @@ void MainWindow::onConfigSaved()
void MainWindow::OnStatusUpdate(const QString &statusMessage)
{
statusBar()->showMessage(statusMessage);
LOG_DEBUG("Status update: %s", statusMessage.toStdString().c_str());
LOG_DEBUG("Status update: %s \n", statusMessage.toStdString().c_str());
}
// 回调需要显示几个图像
@ -211,14 +211,14 @@ void MainWindow::OnServerConnected(const QString &serverName)
{
QString message = QString("已连接到服务器: %1").arg(serverName);
statusBar()->showMessage(message);
LOG_DEBUG("%s", message.toStdString().c_str());
LOG_DEBUG("%s \n", message.toStdString().c_str());
}
void MainWindow::OnServerDisconnected(const QString &serverName)
{
QString message = QString("与服务器断开连接: %1").arg(serverName);
statusBar()->showMessage(message);
LOG_DEBUG("%s", message.toStdString().c_str());
LOG_DEBUG("%s \n", message.toStdString().c_str());
}
void MainWindow::OnWorkStatusChanged(BeltTearingWorkStatus status)
@ -250,12 +250,12 @@ void MainWindow::OnWorkStatusChanged(BeltTearingWorkStatus status)
QString message = QString("工作状态: %1").arg(statusStr);
statusBar()->showMessage(message);
LOG_DEBUG("%s", message.toStdString().c_str());
LOG_DEBUG("%s \n", message.toStdString().c_str());
}
void MainWindow::OnErrorOccurred(const QString &errorMessage)
{
statusBar()->showMessage("错误: " + errorMessage);
LOG_ERROR("Error occurred: %s", errorMessage.toStdString().c_str());
LOG_ERROR("Error occurred: %s \n", errorMessage.toStdString().c_str());
}

View File

@ -24,9 +24,9 @@
<property name="geometry">
<rect>
<x>40</x>
<y>34</y>
<y>4</y>
<width>341</width>
<height>51</height>
<height>111</height>
</rect>
</property>
<property name="font">

View File

@ -2,7 +2,7 @@
#define VERSION_H
#define BELT_TEARING_SERVER_VERSION_STRING "1.0.0"
#define BELT_TEARING_SERVER_VERSION_BUILD "1"
#define BELT_TEARING_SERVER_VERSION_BUILD "2"
#define BELT_TEARING_SERVER_PRODUCT_NAME "BeltTearingServer"
#define BELT_TEARING_SERVER_COMPANY_NAME "VisionRobot"
#define BELT_TEARING_SERVER_COPYRIGHT "Copyright (C) 2024 VisionRobot. All rights reserved."

View File

@ -0,0 +1,15 @@
[Unit]
Description=Belt Tearing Detection Server
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/belttearingserver
Environment=LD_LIBRARY_PATH=/opt/sysroot/lib:/usr/lib:/lib
ExecStart=/opt/belttearingserver/BeltTearingServer
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target

View File

@ -986,7 +986,11 @@ int GrabBagPresenter::_OpenDevice(int cameraIndex, const char* cameraName, const
IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice);
int nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet);
if(nRet != SUCCESS){
delete pDevice;
LOG_ERROR("InitDevice failed, error code: %d\n", nRet);
ERR_CODE_RETURN(nRet);
}
// 先设置状态回调
nRet = pDevice->SetStatusCallback(&GrabBagPresenter::_StaticCameraNotify, this);

View File

@ -5,13 +5,14 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TEMPLATE = app
CONFIG += c++11
# Add /utf-8 flag only for MSVC builds to enforce UTF-8 encoding
win32-msvc {
CONFIG += c++11
QMAKE_CXXFLAGS += /utf-8
}else{
CONFIG += c++17
}
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
@ -41,6 +42,7 @@ SOURCES += \
Presenter/Src/ConfigManager.cpp \
Utils/Src/PathManager.cpp \
devstatus.cpp \
dialogalgoarg.cpp \
dialogcamera.cpp \
dialogcameralevel.cpp \
main.cpp \
@ -58,6 +60,7 @@ HEADERS += \
IYLapWeldStatus.h \
Version.h \
devstatus.h \
dialogalgoarg.h \
dialogcamera.h \
dialogcameralevel.h \
mainwindow.h \
@ -65,6 +68,7 @@ HEADERS += \
FORMS += \
devstatus.ui \
dialogalgoarg.ui \
dialogcamera.ui \
dialogcameralevel.ui \
mainwindow.ui \
@ -75,21 +79,21 @@ RESOURCES += \
win32:CONFIG(debug, debug|release) {
LIBS += -L../../../VrUtils/debug -lVrUtils
LIBS += -L../../../CloudUtils/debug -lCloudUtils
LIBS += -L../LapWeldConfig/debug -lLapWeldConfig
LIBS += -L../../../VrEyeDevice/debug -lVrEyeDevice
LIBS += -L../../../VrUtils/debug -lVrUtils
LIBS += -L../../../CloudUtils/debug -lCloudUtils
LIBS += -L../LapWeldConfig/debug -lLapWeldConfig
LIBS += -L../../../VrEyeDevice/debug -lVrEyeDevice
LIBS += -L../../../Module/ModbusTCPServer/debug -lModbusTCPServer
LIBS += -L../../../Module/ShareMem/debug -lShareMem
LIBS += -L../../../VrNets/debug -lVrModbus
LIBS += -L../../../Module/ShareMem/debug -lShareMem
LIBS += -L../../../VrNets/debug -lVrModbus
}else:win32:CONFIG(release, debug|release){
LIBS += -L../../../VrUtils/release -lVrUtils
LIBS += -L../../../CloudUtils/release -lCloudUtils
LIBS += -L../LapWeldConfig/release -lLapWeldConfig
LIBS += -L../../../VrEyeDevice/release -lVrEyeDevice
LIBS += -L../../../VrUtils/release -lVrUtils
LIBS += -L../../../CloudUtils/release -lCloudUtils
LIBS += -L../LapWeldConfig/release -lLapWeldConfig
LIBS += -L../../../VrEyeDevice/release -lVrEyeDevice
LIBS += -L../../../Module/ModbusTCPServer/release -lModbusTCPServer
LIBS += -L../../../Module/ShareMem/release -lShareMem
LIBS += -L../../../VrNets/release -lVrModbus
LIBS += -L../../../Module/ShareMem/release -lShareMem
LIBS += -L../../../VrNets/release -lVrModbus
}else:unix:!macx {
# Unix/Linux平台库链接(包括交叉编译)
# 注意链接顺序:依赖关系从高到低
@ -137,8 +141,8 @@ else:win32:CONFIG(debug, debug|release): {
LIBS += -L$$PWD/../../../SDK/OpenCV320/Windows/vc14/Release -lopencv_world320
}
else:unix:!macx: {
LIBS += -L$$PWD/../SDK/lapWeldDetection/Arm/aarch64 -llapWeldDetection
LIBS += -L$$PWD/../SDK/OpenCV320/Arm/aarch64 -lopencv_core -lopencv_imgproc -lopencv_highgui
LIBS += -L$$PWD/../../../SDK/lapWeldDetection/Arm/aarch64 -llapWeldDetection -lbaseAlgorithm
LIBS += -L$$PWD/../../../SDK/OpenCV320/Arm/aarch64 -lopencv_core -lopencv_imgproc -lopencv_highgui
}
# 添加libmodbus依赖

View File

@ -1,5 +1,5 @@
#pragma once
#include <iostream>
#include <vector>
#include <memory>
#include <QString>

View File

@ -149,7 +149,7 @@ private:
WorkStatus m_currentWorkStatus = WorkStatus::Error; // 当前工作状态
int m_currentCameraIndex = 0; // 当前使用的相机编号
std::atomic<bool> m_bAlgoDetectThreadRunning = false;
std::atomic<bool> m_bAlgoDetectThreadRunning{false};
std::mutex m_algoDetectMutex;
std::condition_variable m_algoDetectCondition;
std::thread m_algoDetectThread; // 算法检测线程

View File

@ -105,6 +105,7 @@ int DetectPresenter::DetectLapWeld(
LOG_INFO("[Algo Thread] Tree Grow: yDeviation_max=%.1f, zDeviation_max=%.1f, maxLineSkipNum=%d, maxSkipDistance=%.1f, minLTypeTreeLen=%.1f, minVTypeTreeLen=%.1f\n",
growParam.yDeviation_max, growParam.zDeviation_max, growParam.maxLineSkipNum,
growParam.maxSkipDistance, growParam.minLTypeTreeLen, growParam.minVTypeTreeLen);
}
// 准备平面校准参数
SSG_planeCalibPara groundCalibPara;
@ -155,6 +156,9 @@ int DetectPresenter::DetectLapWeld(
std::vector<std::vector<SVzNL3DPoint>> objOps;
sx_getLapWeldPostion(xyzData, cornerParam, growParam, lapWeldParam, groundCalibPara, objOps, &errCode);
LOG_DEBUG("sx_getLapWeldPostion : res num %zd err : %d runtime: %.3fms \n", objOps.size(), errCode, oTimeUtils.GetElapsedTimeInMilliSec());
for(size_t i = 0; i < objOps.size(); i++){
LOG_DEBUG(" %d num : %zd \n", i, objOps[i].size());
}
ERR_CODE_RETURN(errCode);
// 从点云数据生成投影图像
@ -162,35 +166,35 @@ int DetectPresenter::DetectLapWeld(
// 转换检测结果为UI显示格式使用机械臂坐标系数据
for (size_t i = 0; i < objOps.size(); i++) {
if (objOps[i].empty()) {
continue;
}
const SVzNL3DPoint& obj = objOps[i][0]; // 使用第一个点作为参考
// 进行坐标转换:从算法坐标系转换到机械臂坐标系
SVzNL3DPoint targetObj;
targetObj.x = obj.x;
targetObj.y = obj.y;
targetObj.z = obj.z;
SVzNL3DPoint robotObj;
CVrConvert::EyeToRobot(targetObj, robotObj, clibMatrix);
// 创建位置数据(使用转换后的机械臂坐标)
LapWeldPosition pos;
pos.x = robotObj.x; // 机械臂坐标X
pos.y = robotObj.y; // 机械臂坐标Y
pos.z = robotObj.z; // 机械臂坐标Z
pos.roll = 0.0; // 搭接焊缝检测不提供姿态角
pos.pitch = 0.0; // 搭接焊缝检测不提供姿态角
pos.yaw = 0.0; // 搭接焊缝检测不提供姿态角
detectionResult.positions.push_back(pos);
if(debugParam.enableDebug && debugParam.printDetailLog){
LOG_INFO("[Algo Thread] Object %zu Eye Coords: X=%.2f, Y=%.2f, Z=%.2f\n", i, obj.x, obj.y, obj.z);
LOG_INFO("[Algo Thread] Object %zu Robot Coords: X=%.2f, Y=%.2f, Z=%.2f, Roll=%.2f, Pitch=%.2f, Yaw=%.2f\n",
i, pos.x, pos.y, pos.z, pos.roll, pos.pitch, pos.yaw);
for(size_t j = 0; j < objOps[i].size(); j++){
const SVzNL3DPoint& obj = objOps[i][j];
// 进行坐标转换:从算法坐标系转换到机械臂坐标系
SVzNL3DPoint targetObj;
targetObj.x = obj.x;
targetObj.y = obj.y;
targetObj.z = obj.z;
SVzNL3DPoint robotObj;
CVrConvert::EyeToRobot(targetObj, robotObj, clibMatrix);
// 创建位置数据(使用转换后的机械臂坐标)
LapWeldPosition pos;
pos.x = robotObj.x; // 机械臂坐标X
pos.y = robotObj.y; // 机械臂坐标Y
pos.z = robotObj.z; // 机械臂坐标Z
pos.roll = 0.0; // 搭接焊缝检测不提供姿态角
pos.pitch = 0.0; // 搭接焊缝检测不提供姿态角
pos.yaw = 0.0; // 搭接焊缝检测不提供姿态角
detectionResult.positions.push_back(pos);
if(debugParam.enableDebug && debugParam.printDetailLog){
LOG_INFO("[Algo Thread] Object %zu Eye Coords: X=%.2f, Y=%.2f, Z=%.2f\n", i, obj.x, obj.y, obj.z);
LOG_INFO("[Algo Thread] Object %zu Robot Coords: X=%.2f, Y=%.2f, Z=%.2f, Roll=%.2f, Pitch=%.2f, Yaw=%.2f\n",
i, pos.x, pos.y, pos.z, pos.roll, pos.pitch, pos.yaw);
}
}
}
@ -209,4 +213,4 @@ int DetectPresenter::DetectLapWeld(
}
return nRet;
}
}

View File

@ -23,12 +23,20 @@ QString PathManager::GetCalibrationFilePath()
QString PathManager::GetAppConfigDirectory()
{
QString configDir = "";
// #ifdef _WIN32
// // Windows系统使用程序目录
// configDir = GetProgramDirectory();
// #else
// // Linux系统使用用户配置目录
// configDir = QDir::homePath() + "/.config/LapWeldApp/Config";
// #endif
// return configDir + "/../LapWeldApp/Config";
#ifdef _WIN32
// Windows系统使用程序目录
configDir = GetProgramDirectory();
#else
// Linux系统使用用户配置目录
configDir = QDir::homePath() + "/.config/LapWeldApp/Config";
// Linux系统使用用户配置目录
configDir = GetUserConfigDirectory();
#endif
return configDir + "/../LapWeldApp/Config";
}

View File

@ -2,9 +2,9 @@
#define VERSION_H
#define LAPWELD_VERSION_STRING "1.1.3"
#define LAPWELD_VERSION_STRING "1.0.0"
#define LAPWELD_BUILD_STRING "1"
#define LAPWELD_FULL_VERSION_STRING "V1.1.3_1"
#define LAPWELD_FULL_VERSION_STRING "V1.0.0_1"
// 获取版本信息的便捷函数
inline const char* GetLapWeldVersion() {

View File

@ -0,0 +1,102 @@
#include "dialogalgoarg.h"
#include "ui_dialogalgoarg.h"
#include <QMessageBox>
#include <QPushButton>
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
#include <QtCore/QFile>
#include "PathManager.h"
DialogAlgoarg::DialogAlgoarg(IVrConfig* vrConfig, QWidget *parent)
: QDialog(parent)
, ui(new Ui::DialogAlgoarg)
, m_vrConfig(vrConfig)
{
ui->setupUi(this);
// 隐藏标题栏
setWindowFlags(Qt::FramelessWindowHint);
// 获取配置文件路径
m_configFilePath = PathManager::GetConfigFilePath();
// 从配置文件加载数据到界面
LoadConfigToUI();
}
DialogAlgoarg::~DialogAlgoarg()
{
delete ui;
}
void DialogAlgoarg::LoadConfigToUI()
{
if (!m_vrConfig) {
return;
}
try {
// 加载配置文件
m_configData = m_vrConfig->LoadConfig(m_configFilePath.toStdString());
// 将激光焊接参数加载到界面控件
const VrLapWeldParam& lapWeldParam = m_configData.algorithmParams.lapWeldParam;
// 设置参数到界面
ui->lineEdit_lapHeight->setText(QString::number(lapWeldParam.lapHeight));
ui->lineEdit_weldMinLen->setText(QString::number(lapWeldParam.weldMinLen));
ui->lineEdit_weldRefPoints->setText(QString::number(lapWeldParam.weldRefPoints));
// 设置扫描模式下拉框
ui->comboBox_scanMode->setCurrentIndex(static_cast<int>(lapWeldParam.scanMode));
} catch (const std::exception& e) {
QMessageBox::critical(this, "错误", "加载配置文件失败!");
}
}
bool DialogAlgoarg::SaveConfigFromUI()
{
if (!m_vrConfig) {
return false;
}
try {
// 从界面控件读取参数
VrLapWeldParam& lapWeldParam = m_configData.algorithmParams.lapWeldParam;
// 读取参数
lapWeldParam.lapHeight = ui->lineEdit_lapHeight->text().toDouble();
lapWeldParam.weldMinLen = ui->lineEdit_weldMinLen->text().toDouble();
lapWeldParam.weldRefPoints = ui->lineEdit_weldRefPoints->text().toInt();
// 读取扫描模式
lapWeldParam.scanMode = static_cast<WeldScanMode>(ui->comboBox_scanMode->currentIndex());
// 保存配置文件
bool success = m_vrConfig->SaveConfig(m_configFilePath.toStdString(), m_configData);
return success;
} catch (const std::exception& e) {
return false;
}
}
void DialogAlgoarg::on_btn_camer_ok_clicked()
{
if (SaveConfigFromUI()) {
QMessageBox::information(this, "成功", "配置保存成功!");
accept();
} else {
QMessageBox::warning(this, "失败", "配置保存失败,请检查文件权限!");
}
}
void DialogAlgoarg::on_btn_camer_cancel_clicked()
{
// 直接关闭窗口,不保存任何更改
reject();
}

View File

@ -0,0 +1,36 @@
#ifndef DIALOGALGOARG_H
#define DIALOGALGOARG_H
#include <QWidget>
#include <QDialog>
#include <QString>
#include "IVrConfig.h"
namespace Ui {
class DialogAlgoarg;
}
class DialogAlgoarg : public QDialog
{
Q_OBJECT
public:
explicit DialogAlgoarg(IVrConfig* vrConfig, QWidget *parent = nullptr);
~DialogAlgoarg();
private slots:
void on_btn_camer_ok_clicked();
void on_btn_camer_cancel_clicked();
private:
void LoadConfigToUI();
bool SaveConfigFromUI();
private:
Ui::DialogAlgoarg *ui;
IVrConfig* m_vrConfig;
ConfigResult m_configData;
QString m_configFilePath;
};
#endif // DIALOGALGOARG_H

View File

@ -0,0 +1,265 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogAlgoarg</class>
<widget class="QWidget" name="DialogAlgoarg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>566</width>
<height>412</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(25, 26, 28);</string>
</property>
<widget class="QPushButton" name="btn_camer_cancel">
<property name="geometry">
<rect>
<x>340</x>
<y>340</y>
<width>111</width>
<height>38</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/dialog_cancel.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_camer_ok">
<property name="geometry">
<rect>
<x>110</x>
<y>340</y>
<width>111</width>
<height>38</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/dialog_ok.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QLabel" name="label_camera_title">
<property name="geometry">
<rect>
<x>40</x>
<y>20</y>
<width>491</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);</string>
</property>
<property name="text">
<string>算法参数</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>50</x>
<y>70</y>
<width>451</width>
<height>250</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);</string>
</property>
<property name="title">
<string>激光焊接参数</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>22</x>
<y>42</y>
<width>411</width>
<height>201</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);</string>
</property>
<property name="text">
<string>搭接厚度</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);</string>
</property>
<property name="text">
<string>最小焊缝长度</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);</string>
</property>
<property name="text">
<string>参考点数</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);</string>
</property>
<property name="text">
<string>扫描模式</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="lineEdit_lapHeight">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);
background-color: rgb(47, 48, 52);</string>
</property>
<property name="inputMethodHints">
<set>Qt::ImhFormattedNumbersOnly</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_weldMinLen">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);
background-color: rgb(47, 48, 52);</string>
</property>
<property name="inputMethodHints">
<set>Qt::ImhFormattedNumbersOnly</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_weldRefPoints">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);
background-color: rgb(47, 48, 52);</string>
</property>
<property name="inputMethodHints">
<set>Qt::ImhDigitsOnly</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_scanMode">
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);
background-color: rgb(47, 48, 52);</string>
</property>
<item>
<property name="text">
<string>垂直扫描</string>
</property>
</item>
<item>
<property name="text">
<string>水平扫描</string>
</property>
</item>
<item>
<property name="text">
<string>双向扫描</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,106 +1,106 @@
#ifndef DialogCameraLevel_H
#define DialogCameraLevel_H
#include <QDialog>
#include <QWidget>
#include <QComboBox>
#include <QLineEdit>
#include <QMessageBox>
#include <QThread>
#include <vector>
#include <mutex>
#include "IVrEyeDevice.h"
#include "LapWeldPresenter.h"
#include "VZNL_Types.h"
// #define LEVEL_DEBUG_MODE
namespace Ui {
class DialogCameraLevel;
}
class DialogCameraLevel : public QDialog
{
Q_OBJECT
public:
explicit DialogCameraLevel(QWidget *parent = nullptr);
~DialogCameraLevel();
// Delete copy constructor and assignment operator due to atomic members
DialogCameraLevel(const DialogCameraLevel&) = delete;
DialogCameraLevel& operator=(const DialogCameraLevel&) = delete;
// 设置相机列表和presenter
void setCameraList(const std::vector<std::pair<std::string, IVrEyeDevice*>>& cameraList,
LapWeldPresenter* presenter);
private slots:
void on_btn_apply_clicked();
void on_btn_cancel_clicked();
void on_combo_camera_currentIndexChanged(int index);
private:
Ui::DialogCameraLevel *ui;
// 相机列表和名称
std::vector<std::pair<std::string, IVrEyeDevice*>> m_cameraList;
LapWeldPresenter* m_presenter = nullptr;
// 扫描数据缓存
std::vector<SVzNL3DLaserLine> m_scanDataCache;
std::mutex m_scanDataMutex;
// 状态回调相关
std::atomic<bool> m_swingFinished = false; // 摆动完成标志,同时表示扫描完成
std::atomic<bool> m_callbackRestored = false;
// 初始化相机选择框
void initializeCameraCombo();
// 执行相机调平
bool performCameraLeveling();
// 直接使用相机接口进行扫描
bool startCameraScan(int cameraIndex);
bool stopCameraScan(int cameraIndex);
// 检测数据回调函数
static void StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData);
void DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint);
// 状态回调函数
static void StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
void StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
// 设置和恢复状态回调
void setLevelingStatusCallback();
void restorePresenterStatusCallback();
// 处理扫描到的地面数据进行调平计算
bool calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9]);
// 清空扫描数据缓存
void clearScanDataCache();
// Debug模式方法
QString selectDebugDataFile();
bool loadDebugDataAndSimulateScan(const QString& filePath);
void simulateScanProcess();
// 更新调平结果显示
void updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9]);
// 保存调平结果到配置
bool saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9], int cameraIndex, const QString& cameraName);
// 加载相机标定数据
bool loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
double planeCalib[9], double& planeHeight, double invRMatrix[9]);
// 检查并显示相机标定状态
void checkAndDisplayCalibrationStatus(int cameraIndex);
};
#endif // DialogCameraLevel_H
#ifndef DialogCameraLevel_H
#define DialogCameraLevel_H
#include <QDialog>
#include <QWidget>
#include <QComboBox>
#include <QLineEdit>
#include <QMessageBox>
#include <QThread>
#include <vector>
#include <mutex>
#include "IVrEyeDevice.h"
#include "LapWeldPresenter.h"
#include "VZNL_Types.h"
// #define LEVEL_DEBUG_MODE
namespace Ui {
class DialogCameraLevel;
}
class DialogCameraLevel : public QDialog
{
Q_OBJECT
public:
explicit DialogCameraLevel(QWidget *parent = nullptr);
~DialogCameraLevel();
// Delete copy constructor and assignment operator due to atomic members
DialogCameraLevel(const DialogCameraLevel&) = delete;
DialogCameraLevel& operator=(const DialogCameraLevel&) = delete;
// 设置相机列表和presenter
void setCameraList(const std::vector<std::pair<std::string, IVrEyeDevice*>>& cameraList,
LapWeldPresenter* presenter);
private slots:
void on_btn_apply_clicked();
void on_btn_cancel_clicked();
void on_combo_camera_currentIndexChanged(int index);
private:
Ui::DialogCameraLevel *ui;
// 相机列表和名称
std::vector<std::pair<std::string, IVrEyeDevice*>> m_cameraList;
LapWeldPresenter* m_presenter = nullptr;
// 扫描数据缓存
std::vector<SVzNL3DLaserLine> m_scanDataCache;
std::mutex m_scanDataMutex;
// 状态回调相关
std::atomic<bool> m_swingFinished = false; // 摆动完成标志,同时表示扫描完成
std::atomic<bool> m_callbackRestored = false;
// 初始化相机选择框
void initializeCameraCombo();
// 执行相机调平
bool performCameraLeveling();
// 直接使用相机接口进行扫描
bool startCameraScan(int cameraIndex);
bool stopCameraScan(int cameraIndex);
// 检测数据回调函数
static void StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData);
void DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint);
// 状态回调函数
static void StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
void StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
// 设置和恢复状态回调
void setLevelingStatusCallback();
void restorePresenterStatusCallback();
// 处理扫描到的地面数据进行调平计算
bool calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9]);
// 清空扫描数据缓存
void clearScanDataCache();
// Debug模式方法
QString selectDebugDataFile();
bool loadDebugDataAndSimulateScan(const QString& filePath);
void simulateScanProcess();
// 更新调平结果显示
void updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9]);
// 保存调平结果到配置
bool saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9], int cameraIndex, const QString& cameraName);
// 加载相机标定数据
bool loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
double planeCalib[9], double& planeHeight, double invRMatrix[9]);
// 检查并显示相机标定状态
void checkAndDisplayCalibrationStatus(int cameraIndex);
};
#endif // DialogCameraLevel_H

View File

@ -492,6 +492,7 @@ void MainWindow::on_btn_stop_clicked()
m_presenter->StopDetection();
}
void MainWindow::on_btn_camera_clicked()
{
// 检查是否有其他按钮已被选中
@ -510,20 +511,65 @@ void MainWindow::on_btn_camera_clicked()
setButtonSelectedState(ui->btn_camera, true);
// 使用新的相机列表获取功能
// 如果对话框不存在创建新的DialogCamera
if (nullptr == ui_dialogCamera) {
ui_dialogCamera = new DialogCamera(m_presenter->GetCameraList(), this);
// 连接对话框关闭信号
connect(ui_dialogCamera, &QDialog::finished, this, [this]() {
setButtonSelectedState(ui->btn_camera, false);
});
}
ui_dialogCamera->show();
}
void MainWindow::on_btn_algo_config_clicked()
{
// 检查是否有其他按钮已被选中
if (m_selectedButton != nullptr && m_selectedButton != ui->btn_algo_config) {
updateStatusLog(tr("请先关闭当前打开的配置窗口"));
return;
}
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 设置当前按钮为选中状态
setButtonSelectedState(ui->btn_algo_config, true);
// 获取配置对象
IVrConfig* config = m_presenter->GetConfig();
if (!config) {
// 恢复按钮状态
setButtonSelectedState(ui->btn_algo_config, false);
// 设置白色字体的警告消息框
QMessageBox msgBox;
msgBox.setWindowTitle("错误");
msgBox.setText("配置模块未正确初始化!");
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStyleSheet("QMessageBox { color: white; }");
msgBox.exec();
return;
}
if(nullptr == ui_dialogConfig){
ui_dialogConfig = new DialogAlgoarg(config, this);
// 连接对话框关闭信号
connect(ui_dialogConfig, &QDialog::finished, this, [this]() {
setButtonSelectedState(ui->btn_algo_config, false);
});
}
ui_dialogConfig->show();
}
void MainWindow::on_btn_camera_levelling_clicked()
{
// 检查是否有其他按钮已被选中
@ -643,7 +689,7 @@ void MainWindow::setButtonsEnabled(bool enabled)
void MainWindow::setButtonImage(QPushButton* button, const QString& imagePath)
{
if (button) {
QString styleSheet = QString("image: url(%1);").arg(imagePath);
QString styleSheet = QString("image: url(%1);background-color: rgb(38, 40, 47);border: none;").arg(imagePath);
button->setStyleSheet(styleSheet);
}
}
@ -914,3 +960,5 @@ bool MainWindow::saveDetectionDataToFile(const QString& filePath, int cameraInde
}
}

View File

@ -13,6 +13,7 @@
#include <QMenu>
#include <QAction>
#include "dialogcamera.h"
#include "dialogalgoarg.h"
#include "dialogcameralevel.h"
#include "devstatus.h"
#include "LapWeldPresenter.h"
@ -79,6 +80,8 @@ private slots:
void on_btn_camera_clicked();
void on_btn_algo_config_clicked();
void on_btn_camera_levelling_clicked();
void on_btn_hide_clicked();
@ -90,9 +93,11 @@ private slots:
// 右键菜单相关槽函数
void onSaveDetectionData();
private:
Ui::MainWindow * ui;
DialogCamera* ui_dialogCamera = nullptr;
DialogAlgoarg* ui_dialogConfig = nullptr;
DialogCameraLevel* ui_dialogCameraLevel = nullptr;
// 业务逻辑处理类

View File

@ -59,9 +59,9 @@ color: rgb(239, 241, 245);</string>
<property name="geometry">
<rect>
<x>40</x>
<y>34</y>
<y>14</y>
<width>341</width>
<height>51</height>
<height>91</height>
</rect>
</property>
<property name="font">

View File

@ -94,12 +94,12 @@ struct VrSlopeParam
*/
struct VrCornerParam
{
double cornerTh = 30; // 拐角阈值
double cornerTh = 25; // 拐角阈值
double scale = 4; // 计算方向角的窗口比例因子
double minEndingGap = 20; // Y方向最小结束间隔
double minEndingGap_z = 20; // Z方向最小结束间隔
double minEndingGap = 6; // Y方向最小结束间隔
double minEndingGap_z = 1.5; // Z方向最小结束间隔
double jumpCornerTh_1 = 10; // 跳跃拐角阈值1
double jumpCornerTh_2 = 30; // 跳跃拐角阈值2
double jumpCornerTh_2 = 25; // 跳跃拐角阈值2
};
/**

View File

@ -2,16 +2,10 @@
<LapWeldConfig>
<AlgorithmParams>
<!-- 离群点滤波参数 -->
<OutlierFilterParam continuityTh="20.0" outlierTh="5" />
<!-- 角点特征参数 -->
<CornerParam minEndingGap="20.0" minEndingGap_z="20.0" scale="4.0" cornerTh="30.0"
jumpCornerTh_1="10.0" jumpCornerTh_2="30.0" />
<!-- 斜率参数 -->
<SlopeParam LSlopeZWin="10.0" validSlopeH="5.0" minLJumpH="3.0" minEndingGap="2.0" />
<!-- 增长参数 -->
<GrowParam maxLineSkipNum="5" yDeviation_max="1.0" maxSkipDistance="5.0"
zDeviation_max="2.0" minLTypeTreeLen="30.0" minVTypeTreeLen="30.0" />

View File

@ -19,10 +19,8 @@ SUBDIRS += ../CloudUtils/CloudUtils.pro
SUBDIRS += ../App/GrabBag/GrabBag.pro
# 撕裂项目
# SUBDIRS += ../App/BeltTearing/BeltTearing.pro
SUBDIRS += ../App/BeltTearing/BeltTearing.pro
#焊接
# SUBDIRS += ../App/LapWeld/LapWeld.pro
SUBDIRS += ../App/LapWeld/LapWeld.pro

View File

@ -7,7 +7,7 @@ cd /d "%PRJ_PATH%\buildwin\BeltTearingApp"
powershell -Command "Remove-Item * -Recurse -Force"
copy "..\..\build\BeltTearingApp\release\BeltTearingApp.exe" .\
copy "..\..\build\App\BeltTearing\BeltTearingApp\release\BeltTearingApp.exe" .\
"C:\tools\Qt\5.15.2\msvc2019_64\bin\windeployqt.exe" "BeltTearingApp.exe"

View File

@ -5,7 +5,7 @@ PKG_NAME="BeltTearingServer"
PKG_ARCH="arm64"
# 从Version.h文件中读取版本信息
VERSION_FILE="../BeltTearingServer/Version.h"
VERSION_FILE="../App/BeltTearing/BeltTearingServer/Version.h"
if [ -f "${VERSION_FILE}" ]; then
# 读取版本号(从 BELT_TEARING_SERVER_VERSION_STRING 中提取)
@ -54,14 +54,31 @@ mkdir -p ${PKG_PATH}/DEBIAN
mkdir -p ${PKG_PATH}/usr/lib
mkdir -p ${PKG_PATH}/etc/profile.d
mkdir -p ${PKG_PATH}/opt/belttearingserver
mkdir -p ${PKG_PATH}/opt/sysroot/lib
echo "复制 Qt 运行时环境..."
#QT depend
QT_PKG_PATH=/opt/firefly_qt5.15_arm64_20.04
QT_LIB_PATH=/opt/sysroot/firefly-arm64-sysroot-20.04/lib/aarch64-linux-gnu
cp -rfd ${QT_PKG_PATH}/ext ${PKG_PATH}/opt/firefly_qt5.15
cp ${QT_PKG_PATH}/target_qtEnv.sh ${PKG_PATH}/etc/profile.d/
# 复制 Qt 库文件
for libfile in ${QT_LIB_PATH}/*.so*; do
# 获取文件名用于比较
filename=$(basename "$libfile")
# 跳过 LLVM、flite、clang 和 X11 相关库文件
if [[ "$filename" == *icu* ]]; then
# 复制其他库文件,保持符号链接
cp -rfd "$libfile" ${PKG_PATH}/opt/sysroot/lib/
continue
fi
done
echo "复制依赖库文件..."
#depend
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_core*.so* ${PKG_PATH}/usr/lib/
@ -76,7 +93,10 @@ cp ${CODE_PATH}/SDK/VzNLSDK/Arm/aarch64/*.so ${PKG_PATH}/usr/lib/
echo "复制 BeltTearingServer 内容到 /opt/..."
#APP
cp ${CODE_PATH}/GrabBagPrj/buildarm/BeltTearingServer/BeltTearingServer ${PKG_PATH}/opt/belttearingserver/
cp ${CODE_PATH}/GrabBagPrj/buildarm/App/BeltTearing/BeltTearingServer/BeltTearingServer ${PKG_PATH}/opt/belttearingserver/
#service
cp ${CODE_PATH}/App/BeltTearing/BeltTearingServer/belttearingserver.service ${PKG_PATH}/opt/belttearingserver/
echo "生成 control 文件..."
#control

View File

@ -78,7 +78,6 @@ for libfile in ${QT_LIB_PATH}/*.so*; do
cp -rfd "$libfile" ${PKG_PATH}/opt/sysroot/lib/
continue
fi
done
echo "复制依赖库文件..."

333
GrabBagPrj/pkg_lapweld.sh Normal file
View File

@ -0,0 +1,333 @@
#!/bin/bash
#lapweld 版本配置
PKG_NAME="LapWeld"
PKG_ARCH="arm64"
# 从Version.h文件中读取版本信息
VERSION_FILE="../App/LapWeld/LapWeldApp/Version.h"
if [ -f "${VERSION_FILE}" ]; then
# 读取版本号(从 LAPWELD_VERSION_STRING 中提取)
PKG_VERSION=$(grep '#define LAPWELD_VERSION_STRING' ${VERSION_FILE} | sed 's/.*"\(.*\)".*/\1/')
# 读取构建号(从 LAPWELD_BUILD_STRING 中提取)
BUILD_NUMBER=$(grep '#define LAPWELD_BUILD_STRING' ${VERSION_FILE} | sed 's/.*"\(.*\)".*/\1/')
echo "${VERSION_FILE} 读取版本信息:"
echo " 版本号: ${PKG_VERSION}"
echo " 构建号: ${BUILD_NUMBER}"
# 如果读取失败,使用默认值
if [ -z "${PKG_VERSION}" ]; then
PKG_VERSION="1.0.0"
echo "警告: 无法读取版本号,使用默认值: ${PKG_VERSION}"
fi
if [ -z "${BUILD_NUMBER}" ]; then
BUILD_NUMBER="1"
echo "警告: 无法读取构建号,使用默认值: ${BUILD_NUMBER}"
fi
else
# Version.h文件不存在时的默认值
PKG_VERSION="1.0.0"
BUILD_NUMBER="1"
echo "警告: ${VERSION_FILE} 文件不存在,使用默认版本信息"
echo " 版本号: ${PKG_VERSION}"
echo " 构建号: ${BUILD_NUMBER}"
fi
PKG_PATH=$HOME/LapWeldPkg
CODE_PATH=../
RELEASE_PATH=../Publish
echo "=========================================="
echo "开始打包 LapWeld 应用程序 v${PKG_VERSION}..."
echo "=========================================="
if [ -d "${PKG_PATH}" ];then
echo "清理旧的打包目录..."
rm -irf ${PKG_PATH}
fi
#QT depend
QT_PKG_PATH=/opt/firefly_qt5.15_arm64_20.04
QT_LIB_PATH=/opt/sysroot/firefly-arm64-sysroot-20.04/lib/aarch64-linux-gnu
echo "创建打包目录结构..."
mkdir -p ${PKG_PATH}/DEBIAN
mkdir -p ${PKG_PATH}/etc/profile.d
mkdir -p ${PKG_PATH}/etc/xdg/autostart
mkdir -p ${PKG_PATH}/opt/sysroot/lib
mkdir -p ${PKG_PATH}/usr/local/bin
mkdir -p ${PKG_PATH}/usr/lib
mkdir -p ${PKG_PATH}/usr/share/applications
mkdir -p ${PKG_PATH}/usr/share/pixmaps
echo "复制 Qt 运行时环境..."
cp -rfd ${QT_PKG_PATH}/ext ${PKG_PATH}/opt/firefly_qt5.15
cp ${QT_PKG_PATH}/target_qtEnv.sh ${PKG_PATH}/etc/profile.d/
# 复制 Qt 库文件
for libfile in ${QT_LIB_PATH}/*.so*; do
# 获取文件名用于比较
filename=$(basename "$libfile")
# 跳过 LLVM、flite、clang 和 X11 相关库文件
if [[ "$filename" == *icu* ]]; then
# 复制其他库文件,保持符号链接
cp -rfd "$libfile" ${PKG_PATH}/opt/sysroot/lib/
continue
fi
done
echo "复制依赖库文件..."
#depend
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_core*.so* ${PKG_PATH}/usr/lib/
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_imgproc*.so* ${PKG_PATH}/usr/lib/
cp -a ${CODE_PATH}/SDK/OpenCV320/Arm/aarch64/*opencv_highgui*.so* ${PKG_PATH}/usr/lib/
cp ${CODE_PATH}/SDK/lapWeldDetection/Arm/aarch64/*.so ${PKG_PATH}/usr/lib/
cp ${CODE_PATH}/SDK/VzNLSDK/Arm/aarch64/*.so ${PKG_PATH}/usr/lib/
echo "复制应用程序主文件..."
#APP
cp ${CODE_PATH}/GrabBagPrj/buildarm/App/LapWeld/LapWeldApp/LapWeldApp ${PKG_PATH}/usr/local/bin/
echo "复制应用程序图标..."
#LOGO
cp ${CODE_PATH}/App/LapWeld/LapWeldApp/resource/logo.png ${PKG_PATH}/usr/share/pixmaps/lapweld.png
echo "生成桌面自启动配置文件..."
#desktop autostart configuration
AUTOSTART_PATH=${PKG_PATH}/etc/xdg/autostart/lapweld.desktop
cat > ${AUTOSTART_PATH} << EOF
[Desktop Entry]
Type=Application
Name=LapWeld
Comment=LapWeld Application Auto Start
Exec=/usr/local/bin/LapWeldApp
Icon=/usr/share/pixmaps/lapweld.png
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
AutostartCondition=GNOME3 unless-session gnome
EOF
echo "生成 control 文件..."
#control
CONTROL_PATH=${PKG_PATH}/DEBIAN/control
echo "Package: ${PKG_NAME}" > ${CONTROL_PATH}
echo "Version: ${PKG_VERSION}" >> ${CONTROL_PATH}
echo "Section: lapweldapp" >> ${CONTROL_PATH}
echo "Architecture: ${PKG_ARCH}" >> ${CONTROL_PATH}
echo "Priority: optional" >> ${CONTROL_PATH}
echo "Maintainer: LapWeld Team <support@lapweld.com>" >> ${CONTROL_PATH}
echo "Description: lapweld app" >> ${CONTROL_PATH}
echo "生成安装后脚本..."
#postinst install exec script
POSTINST_PATH=${PKG_PATH}/DEBIAN/postinst
cat > ${POSTINST_PATH} << 'EOF'
#!/bin/bash
echo "配置 LapWeld 应用程序..."
# 设置库文件路径
echo "/usr/lib" > /etc/ld.so.conf.d/lapweld.conf
echo "/opt/sysroot/lib/" >> /etc/ld.so.conf.d/lapweld.conf
ldconfig
# 确保应用程序可执行
chmod +x /usr/local/bin/LapWeldApp
# 配置端口映射 502 -> 5020
echo "配置端口映射 502 -> 5020..."
iptables -t nat -A PREROUTING -p tcp --dport 502 -j REDIRECT --to-port 5020
# 检查并创建systemd服务确保重启后规则生效
if [ ! -f /etc/systemd/system/lapweld-port-mapping.service ]; then
echo "创建端口映射服务..."
cat > /etc/systemd/system/lapweld-port-mapping.service << 'PORTEOF'
[Unit]
Description=LapWeld Port Mapping Service
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'iptables -t nat -A PREROUTING -p tcp --dport 502 -j REDIRECT --to-port 5020'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
PORTEOF
systemctl enable lapweld-port-mapping.service
systemctl start lapweld-port-mapping.service
else
echo "端口映射服务已存在,跳过创建..."
# 确保服务处于启用状态
systemctl enable lapweld-port-mapping.service 2>/dev/null || true
systemctl start lapweld-port-mapping.service 2>/dev/null || true
fi
# 检查并创建当前用户的桌面快捷方式
echo "检查当前用户的桌面快捷方式..."
# 获取当前执行安装的用户信息
if [ -n "$SUDO_USER" ]; then
# 如果是通过sudo执行的获取真实用户
current_user="$SUDO_USER"
current_home=$(getent passwd "$current_user" | cut -d: -f6)
else
# 直接执行的情况
current_user=$(whoami)
current_home="$HOME"
fi
echo "当前用户: $current_user"
echo "用户主目录: $current_home"
# 检查多种可能的桌面目录名称
desktop_dirs=("Desktop" "桌面" "desktop")
desktop_dir=""
desktop_shortcut=""
for dir_name in "${desktop_dirs[@]}"; do
potential_dir="$current_home/$dir_name"
if [ -d "$potential_dir" ]; then
desktop_dir="$potential_dir"
desktop_shortcut="$desktop_dir/lapweld.desktop"
echo "找到桌面目录: $desktop_dir"
break
fi
done
# 检查是否找到桌面目录
if [ -n "$desktop_dir" ]; then
# 检查桌面上是否已有快捷方式
if [ ! -f "$desktop_shortcut" ]; then
echo "为当前用户创建桌面快捷方式..."
# 复制桌面文件到用户桌面
cp /usr/share/applications/lapweld.desktop "$desktop_shortcut"
# 设置正确的所有者和权限
chown $current_user:$current_user "$desktop_shortcut" 2>/dev/null || true
chmod 755 "$desktop_shortcut"
echo "已创建桌面快捷方式: $desktop_shortcut"
else
echo "桌面快捷方式已存在,跳过创建"
fi
else
echo "当前用户没有找到桌面目录(Desktop/桌面/desktop),跳过桌面快捷方式创建"
fi
echo "LapWeld 应用程序安装完成!"
echo "应用程序将在用户登录桌面后自动启动。"
echo "端口映射已配置502 -> 5020"
echo "桌面快捷方式已创建如果用户有Desktop目录"
echo "如需立即启动,请运行: /usr/local/bin/LapWeldApp"
echo "如需禁用自启动,请删除文件: ~/.config/autostart/lapweld.desktop"
EOF
chmod +x ${POSTINST_PATH}
echo "生成卸载脚本..."
#postrm uninstall exec script
POSTRM_PATH=${PKG_PATH}/DEBIAN/postrm
cat > ${POSTRM_PATH} << 'EOF'
#!/bin/bash
echo "卸载 LapWeld 应用程序..."
# 清理库文件配置
rm -f /etc/ld.so.conf.d/lapweld.conf
ldconfig
# 清理端口映射配置
echo "清理端口映射配置..."
systemctl stop lapweld-port-mapping.service 2>/dev/null || true
systemctl disable lapweld-port-mapping.service 2>/dev/null || true
rm -f /etc/systemd/system/lapweld-port-mapping.service
# 清理iptables规则
iptables -t nat -D PREROUTING -p tcp --dport 502 -j REDIRECT --to-port 5020 2>/dev/null || true
# 重新加载systemd
systemctl daemon-reload
# 清理当前用户的桌面快捷方式
echo "清理当前用户的桌面快捷方式..."
# 获取当前执行卸载的用户信息
if [ -n "$SUDO_USER" ]; then
# 如果是通过sudo执行的获取真实用户
current_user="$SUDO_USER"
current_home=$(getent passwd "$current_user" | cut -d: -f6)
else
# 直接执行的情况
current_user=$(whoami)
current_home="$HOME"
fi
# 检查多种可能的桌面目录名称并清理快捷方式
desktop_dirs=("Desktop" "桌面" "desktop")
shortcut_found=false
for dir_name in "${desktop_dirs[@]}"; do
desktop_shortcut="$current_home/$dir_name/lapweld.desktop"
if [ -f "$desktop_shortcut" ]; then
echo "删除当前用户的桌面快捷方式: $desktop_shortcut"
rm -f "$desktop_shortcut"
echo "已删除桌面快捷方式: $desktop_shortcut"
shortcut_found=true
fi
done
if [ "$shortcut_found" = false ]; then
echo "当前用户没有找到桌面快捷方式,跳过清理"
fi
echo "LapWeld 应用程序卸载完成!"
echo "端口映射配置已清理"
echo "桌面快捷方式已清理"
echo "如需彻底清理自启动配置,请手动删除: ~/.config/autostart/lapweld.desktop"
EOF
chmod +x ${POSTRM_PATH}
echo "生成桌面快捷方式..."
#desktop
DESKTOP_PATH=${PKG_PATH}/usr/share/applications/lapweld.desktop
echo "[Desktop Entry]" > ${DESKTOP_PATH}
echo "Version=${PKG_VERSION}" >> ${DESKTOP_PATH}
echo "Name=LapWeld" >> ${DESKTOP_PATH}
echo "Type=Application" >> ${DESKTOP_PATH}
echo "Comment=LapWeld App" >> ${DESKTOP_PATH}
echo "Terminal=false" >> ${DESKTOP_PATH}
echo "Exec=/usr/local/bin/LapWeldApp" >> ${DESKTOP_PATH}
echo "Icon=/usr/share/pixmaps/lapweld.png" >> ${DESKTOP_PATH}
echo "Categories=Development;" >> ${DESKTOP_PATH}
echo "GenericName=LapWeld App" >> ${DESKTOP_PATH}
echo "Keywords=lapweld;app;" >> ${DESKTOP_PATH}
echo "StartupNotify=true" >> ${DESKTOP_PATH}
echo "设置文件权限..."
# 设置usr目录权限不包括DEBIAN
chmod -R 755 ${PKG_PATH}/usr
chmod -R 755 ${PKG_PATH}/etc
chmod -R 755 ${PKG_PATH}/opt
echo "开始构建 DEB 包..."
# 生成带时间戳和构建号的包文件名
TIMESTAMP=$(date +%Y%m%d%H%M%S)
DEB_FILENAME="${RELEASE_PATH}/${PKG_NAME}_${PKG_VERSION}_${BUILD_NUMBER}_${PKG_ARCH}_${TIMESTAMP}.deb"
fakeroot dpkg -b ${PKG_PATH} ${DEB_FILENAME}
echo "=========================================="
echo "打包完成!"
echo "生成的包文件: ${DEB_FILENAME}"
echo "文件大小: $(ls -lh ${DEB_FILENAME} | awk '{print $5}')"
echo "=========================================="

View File

@ -149,7 +149,8 @@ void _outputScanDataFile_vector_h(char* fileName, std::vector<std::vector<SVzNL3
void _outputRGBDScanLapWeld_RGBD(
char* fileName,
std::vector<std::vector<SVzNL3DPosition>>& scanLines,
std::vector< std::vector<SVzNL3DPoint>> weldOPs)
std::vector< std::vector<SVzNL3DPoint>> weldOPs,
bool outDebugInfo)
{
int lineNum = (int)scanLines.size();
std::ofstream sw(fileName);
@ -191,18 +192,38 @@ void _outputRGBDScanLapWeld_RGBD(
for (int i = 0; i < linePtNum; i++)
{
SVzNL3DPosition* pt3D = &scanLines[line][i];
if (pt3D->nPointIdx > 0)
int kkk = 1;
int featureType_v = pt3D->nPointIdx & 0xffff;
int featureType_h = featureType_v >> 4;
featureType_v &= 0xff;
if (LINE_FEATURE_PEAK_TOP == featureType_v)
if (true == outDebugInfo)
{
rgb = { 255, 97, 0 };
size = 5;
}
else if (LINE_FEATURE_PEAK_TOP == featureType_h)
{
rgb = { 97, 255, 0 };
size = 5;
if (LINE_FEATURE_L_JUMP_H2L == featureType_v)
{
rgb = { 255, 97, 0 };
size = 5;
}
else if (LINE_FEATURE_L_JUMP_L2H == featureType_v)
{
rgb = objColor[7];
size = 5;
}
else if (LINE_FEATURE_L_JUMP_H2L == featureType_h)
{
rgb = objColor[6];
size = 5;
}
else if (LINE_FEATURE_L_JUMP_L2H == featureType_h)
{
rgb = { 97, 255, 0 };
size = 5;
}
else
{
rgb = { 200, 200, 200 };
size = 1;
}
}
else
{
@ -225,11 +246,10 @@ void _outputRGBDScanLapWeld_RGBD(
linePtNum += (int)weldOPs[i].size();
sw << "Line_" << lineNum << "_0_" << linePtNum + 1 << std::endl;
rgb = { 0, 0, 255 };
rgb = { 255, 0, 0 };
size = 25;
for (int i = 0; i < weldNum; i++)
{
rgb = objColor[i % 8];
for (int j = 0; j < (int)weldOPs[i].size(); j++)
{
float x = (float)weldOPs[i][j].x;
@ -241,13 +261,37 @@ void _outputRGBDScanLapWeld_RGBD(
}
}
//加一个点用于跳过显示工具bug
rgb = objColor[0];
float x = (float)weldOPs[0][0].x;
float y = (float)weldOPs[0][0].y;
float z = (float)weldOPs[0][0].z;
sw << "{" << x << "," << y << "," << z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << rgb.r << "," << rgb.g << "," << rgb.b << "," << size << " }" << std::endl;
double exLen = 5.0;
rgb = objColor[0];
size = 3;
for (int i = 0; i < weldNum; i++)
{
SVzNL3DPoint pt0 = weldOPs[i][0];
SVzNL3DPoint pt1 = weldOPs[i].back();
double len = sqrt(pow(pt0.x - pt1.x, 2) + pow(pt0.y - pt1.y, 2));
double k = exLen / len;
sw << "Poly_" << i << "_2" << std::endl;
double x = -k * (pt1.x - pt0.x) + pt0.x;
double y = -k * (pt1.y - pt0.y) + pt0.y;
double z = -k * (pt1.z - pt0.z) + pt0.z;
sw << "{" << (float)x << "," << (float)y << "," << (float)z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
x = -k * (pt0.x - pt1.x) + pt1.x;
y = -k * (pt0.y - pt1.y) + pt1.y;
z = -k * (pt0.z - pt1.z) + pt1.z;
sw << "{" << x << "," << y << "," << z << "}-";
sw << "{0,0}-{0,0}-";
sw << "{" << (int)rgb.r << "," << (int)rgb.g << "," << (int)rgb.b << "," << size << "}" << std::endl;
}
}
sw.close();
}
@ -655,7 +699,7 @@ void _convertToGridData(std::vector< std::vector<SVzNL3DPosition>>& scanLines,
#define CONVERT_TO_GRID 0
#define TEST_COMPUTE_CALIB_PARA 0
#define TEST_COMPUTE_GLOVE_POSITION 1
#define TEST_COMPUTE_POSITION 1
#define TEST_GROUP 1
int main()
{
@ -665,7 +709,7 @@ int main()
};
SVzNLRange fileIdx[TEST_GROUP] = {
{0,6}
{1,6}
};
#if CONVERT_TO_GRID
@ -720,7 +764,7 @@ int main()
int kkk = 1;
//行处理
//调平,去除地面
sx_lineDataR(scanData[i], calibPara.planeCalib, -1);// calibPara.planeHeight);
sx_lineDataR(scanData[i], calibPara.planeCalib, -1); // calibPara.planeHeight);
}
//
char calibFile[250];
@ -734,7 +778,7 @@ int main()
}
#endif
#if TEST_COMPUTE_GLOVE_POSITION
#if TEST_COMPUTE_POSITION
for (int grp = 0; grp <= 0; grp++)
{
SSG_planeCalibPara poseCalibPara;
@ -771,7 +815,7 @@ int main()
int kkk = 1;
//行处理
//调平,去除地面
sx_lineDataR(scanLines[i], poseCalibPara.planeCalib, -1);// calibPara.planeHeight);
sx_lineDataR(scanLines[i], poseCalibPara.planeCalib, -1);
}
#if 0
char _out_file[256];
@ -779,24 +823,26 @@ int main()
int headNullLines = 0;
_outputScanDataFile_vector(_out_file, scanLines, false, &headNullLines);
#endif
SSG_treeGrowParam growParam;
growParam.maxLineSkipNum = 5;
growParam.yDeviation_max = 1.0;
growParam.maxSkipDistance = 5.0;
growParam.zDeviation_max = 2;// algoParam.bagParam.bagH / 2; //袋子高度1/2
growParam.minLTypeTreeLen = 30.0; //mm
growParam.minVTypeTreeLen = 30.0; //mm
SSG_cornerParam cornerParam;
cornerParam.cornerTh =30; //45度角
cornerParam.scale = 4; // algoParam.bagParam.bagH / 8; // 15; // algoParam.bagParam.bagH / 8;
cornerParam.minEndingGap = 20;// algoParam.bagParam.bagW / 4;
cornerParam.minEndingGap_z = 20; // algoParam.bagParam.bagH / 4;
cornerParam.jumpCornerTh_1 = 10;
cornerParam.jumpCornerTh_2 = 30;
SSX_lapWeldParam lapWeldParam;
lapWeldParam.lapHeight = 2.0;
lapWeldParam.weldMinLen = 2.0;
lapWeldParam.lapHeight = 1.5;
lapWeldParam.weldMinLen = 80.0;
lapWeldParam.weldRefPoints = 2;
lapWeldParam.scanMode = keSX_ScanMode_V;
SSG_cornerParam cornerParam;
cornerParam.cornerTh = 25; //45度角
cornerParam.scale = 4; // algoParam.bagParam.bagH / 8; // 15; // algoParam.bagParam.bagH / 8;
cornerParam.minEndingGap = 6;// algoParam.bagParam.bagW / 4;
cornerParam.minEndingGap_z = lapWeldParam.lapHeight; // algoParam.bagParam.bagH / 4;
cornerParam.jumpCornerTh_1 = 10;
cornerParam.jumpCornerTh_2 = 25;
SSG_treeGrowParam growParam;
growParam.maxLineSkipNum = 10;
growParam.yDeviation_max = 3.0;
growParam.maxSkipDistance = 5.0;
growParam.zDeviation_max = 1.0;// algoParam.bagParam.bagH / 2; //袋子高度1/2
growParam.minLTypeTreeLen = lapWeldParam.weldMinLen; //mm
growParam.minVTypeTreeLen = lapWeldParam.weldMinLen; //mm
int errCode = 0;
std::vector<std::vector<SVzNL3DPoint>> weldOps;
sx_getLapWeldPostion(
@ -804,6 +850,7 @@ int main()
cornerParam,
growParam,
lapWeldParam,
poseCalibPara,
weldOps,
&errCode);
@ -811,7 +858,7 @@ int main()
printf("%s: %d(ms)!\n", _scan_file, (int)(t2 - t1));
//输出测试结果
sprintf_s(_scan_file, "%sresult\\LaserLine%d_result.txt", dataPath[grp], fidx);
_outputRGBDScanLapWeld_RGBD(_scan_file, scanLines, weldOps);
_outputRGBDScanLapWeld_RGBD(_scan_file, scanLines, weldOps, false);
}
}
#endif

View File

@ -5,10 +5,11 @@
// 前向声明
class CVrTCPClient;
class IVrTCPClient;
// 回调函数类型定义
using TCPRecvFunc = std::function<void(const char* pData, const int nLen)>;
using LinkEventFunc = std::function<void(bool)>;
using TCPRecvFunc = std::function<void(IVrTCPClient* pClient, const char* pData, const int nLen, void* pParam)>;
using LinkEventFunc = std::function<void(IVrTCPClient* pClient, bool connected, void* pParam)>;
/**
* @brief TCP客户端接口类
@ -27,7 +28,7 @@ public:
* @param linkFunc
* @return 0
*/
virtual int LinkDevice(const std::string sDevIP, int nPort, bool bReLink, LinkEventFunc linkFunc) = 0;
virtual int LinkDevice(const std::string sDevIP, int nPort, bool bReLink, LinkEventFunc linkFunc, void* pParam) = 0;
/**
* @brief
@ -40,7 +41,7 @@ public:
* @param fRecvFunc
* @return 0
*/
virtual int StartWork(TCPRecvFunc fRecvFunc) = 0;
virtual int StartWork(TCPRecvFunc fRecvFunc, void* pParam) = 0;
/**
* @brief
@ -61,4 +62,4 @@ public:
* @param pInstance
*/
static void DestroyInstance(IVrTCPClient* pInstance);
};
};

View File

@ -42,9 +42,10 @@ CVrTCPClient::~CVrTCPClient()
}
int CVrTCPClient::LinkDevice(const std::string sDevIP, int nPort, bool bReLink, LinkEventFunc linkFunc)
int CVrTCPClient::LinkDevice(const std::string sDevIP, int nPort, bool bReLink, LinkEventFunc linkFunc, void* pParam)
{
m_fLinkcCallback = linkFunc;
m_pLinkParam = pParam;
m_sIp = sDevIP;
m_nPort = nPort;
@ -53,7 +54,7 @@ int CVrTCPClient::LinkDevice(const std::string sDevIP, int nPort, bool bReLink,
if (SUCCESS == nRet)
{
m_bLink = true;
if (m_fLinkcCallback) m_fLinkcCallback(true);
if (m_fLinkcCallback) m_fLinkcCallback(this, true, pParam);
}
@ -70,12 +71,13 @@ int CVrTCPClient::LinkDevice(const std::string sDevIP, int nPort, bool bReLink,
}
int CVrTCPClient::StartWork(TCPRecvFunc callbackFunc)
int CVrTCPClient::StartWork(TCPRecvFunc fRecvFunc, void* pParam)
{
if (m_bRecv) return SUCCESS;
m_bRecv = true;
m_fRecvCallback = callbackFunc;
m_fRecvCallback = fRecvFunc;
m_pWorkParam = pParam;
std::thread recvThread(&CVrTCPClient::_RecvData, this);
recvThread.detach();
return SUCCESS;
@ -170,16 +172,16 @@ void CVrTCPClient::_RecvData()
if (m_fRecvCallback)
{
m_fRecvCallback(recvData, recvLen);
m_fRecvCallback(this, recvData, recvLen, m_pWorkParam);
}
}
m_bRecvWorking = false;
}
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// 重新连接线程
void CVrTCPClient::_ReLinkDevThread()
{
while (true)
while (m_bRecvWorking)
{
if (m_bLink)
{
@ -188,7 +190,7 @@ void CVrTCPClient::_ReLinkDevThread()
}
m_bLink = ( 0 == _ExecLinkDev(m_sIp, m_nPort) );
if (m_fLinkcCallback) m_fLinkcCallback(m_bLink);
if (m_fLinkcCallback) m_fLinkcCallback(this, m_bLink, m_pLinkParam);
}
}
@ -201,7 +203,7 @@ int CVrTCPClient::_ExecLinkDev(std::string sIP, int nPort)
m_nSocket = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET_VALUE == m_nSocket)
{
if (m_fLinkcCallback) m_fLinkcCallback(false);
if (m_fLinkcCallback) m_fLinkcCallback(this, false, m_pLinkParam);
return ERR_CODE(NET_ERR_CREAT_INIT);
}
@ -219,7 +221,7 @@ int CVrTCPClient::_ExecLinkDev(std::string sIP, int nPort)
if (SOCKET_ERROR_VALUE == nRet)
{
printf("dev connect err [%d] errno : %d\n", nRet, errno);
if (m_fLinkcCallback) m_fLinkcCallback(false);
if (m_fLinkcCallback) m_fLinkcCallback(this, false, m_pLinkParam);
return ERR_CODE(NET_ERR_CONNECT);
}

View File

@ -47,13 +47,13 @@ public:
~CVrTCPClient();
///
int LinkDevice(const std::string sDevIP, int nPort, bool bReLink, LinkEventFunc linkFunc) override;
int LinkDevice(const std::string sDevIP, int nPort, bool bReLink, LinkEventFunc linkFunc, void* pParam) override;
/// ر豸
int CloseDevice() override;
/// ʼܹ
int StartWork(TCPRecvFunc fRecvFunc) override;
int StartWork(TCPRecvFunc fRecvFunc, void* pParam) override;
///
bool SendData(const char* pdata, const int nLen) override;
@ -80,6 +80,10 @@ private:
int _ExecLinkDev(std::string sIP, int nPort);
void* m_pLinkParam;
void* m_pWorkParam;
socket_t m_nSocket;
bool m_bRecv;