拆包更新算法

This commit is contained in:
yiyi 2026-02-06 01:14:27 +08:00
parent 74f9545a65
commit 99881767bb
25 changed files with 215 additions and 79 deletions

View File

@ -224,6 +224,7 @@ int DetectPresenter::DetectBag(
// 1. 使用成员变量算法参数已在初始化时从XML读取
LOG_INFO("[Algo Thread] Using algorithm parameters from XML configuration\n");
LOG_INFO(" Bag: L=%.1f, W=%.1f, H=%.1f\n",algoParam.bagParam.bagL, algoParam.bagParam.bagW, algoParam.bagParam.bagH);
LOG_INFO(" supportRotate=%d, outputMode=%d\n",algoParam.supportRotate, algoParam.outputMode);
LOG_INFO(" Filter: continuityTh=%.1f, outlierTh=%.1f\n", algoParam.filterParam.continuityTh, algoParam.filterParam.outlierTh);
LOG_INFO(" Corner: minEndingGap=%.1f, minEndingGap_z=%.1f, scale=%.1f, cornerTh=%.1f, jumpCornerTh_1=%.1f, jumpCornerTh_2=%.1f\n",

View File

@ -894,6 +894,8 @@ int GrabBagPresenter::InitAlgorithmParams()
LOG_INFO("projectType: %s\n", ProjectTypeToString(m_projectType).c_str());
LOG_INFO("Algorithm parameters initialized successfully via ParameterManager\n");
_UpdateCurrentExecutionParams();
return SUCCESS;
}

View File

@ -2,7 +2,7 @@
#define VERSION_H
#define GRABBAG_VERSION_STRING "1.3.6"
#define GRABBAG_BUILD_STRING "1"
#define GRABBAG_BUILD_STRING "2"
#define GRABBAG_FULL_VERSION_STRING "V" GRABBAG_VERSION_STRING "_" GRABBAG_BUILD_STRING
// 获取版本信息的便捷函数

View File

@ -1,4 +1,7 @@
# 1.3.6
## build_2 20260205
1. 更新算法
## build_1 20260129
1. 增加授权判断

View File

@ -301,7 +301,7 @@ struct VrAlgorithmParams
VrHsvCmpParam hsvCmpParam;
VrRgbColorPattern rgbColorPattern;
VrColorTemplateParam colorTemplateParam;
int supportRotate = 1;
int supportRotate = 0;
int outputMode = 0; // 输出模式0 - 从大到小, 1 - 从小到大
};

View File

@ -19,32 +19,32 @@
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />
</DATA>
<DATA Name="1_x" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2002" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="0" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<DATA Name="1_x" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2002" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="1" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<TIMEOUT Time="2000" ResendCount="0" />
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />
</DATA>
<DATA Name="1_y" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2004" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="0" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<DATA Name="1_y" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2004" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="1" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<TIMEOUT Time="2000" ResendCount="0" />
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />
</DATA>
<DATA Name="1_z" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2006" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="0" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<DATA Name="1_z" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2006" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="1" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<TIMEOUT Time="2000" ResendCount="0" />
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />
</DATA>
<DATA Name="1_r" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2008" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="0" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<DATA Name="1_r" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2008" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="1" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<TIMEOUT Time="2000" ResendCount="0" />
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />
</DATA>
<DATA Name="1_p" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2010" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="0" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<DATA Name="1_p" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2010" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="1" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<TIMEOUT Time="2000" ResendCount="0" />
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />
</DATA>
<DATA Name="1_y" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2012" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="0" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<DATA Name="1_y" BLOCK="2" PrtcTYPE="2" Unit="--" ShowType="0" Addr="2012" Gain="1" Size="2" BitOffset="0" BitNum="32" Range="--" Color="" ByteOder="0" WordOder="1" IntervalTime="0" IsShow="1" IsBRead="1" IsBWrite="0">
<TIMEOUT Time="2000" ResendCount="0" />
<CURVE IsShow="0" />
<VALUE Stategy="0" TimeBngrWay="0" Coef_a="0" Coef_b="0" Coef_c="0" Coef_d="0" Coef_e="0" ResetStep="0" XInvl="1000" MaxRadom="0" MinRadom="0" MaxValue="0" MinValue="0" />

View File

@ -25,6 +25,20 @@ typedef struct
double yawAngle; //偏转角绕Z轴的偏转, 弧度
}SSG_6AxisAttitude;
typedef struct
{
double x;
double y;
double z;
}SWD3DPoint;
typedef struct
{
int lineIdx;
int ptIdx;
SWD3DPoint point;
}SWDIndexing3DPoint;
typedef struct
{
bool validFlag; //指示结果是否有效
@ -48,6 +62,17 @@ typedef struct
int idx;
}SSG_intPair;
typedef struct
{
int featurType;
int featureIdx_v;
int featureIdx_h;
int clusterID;
int flag;
int lineIdx;
int ptIdx;
}SSG_featureClusteringInfo;
typedef struct
{
double left;
@ -56,6 +81,12 @@ typedef struct
double bottom;
}SSG_ROIRectD;
typedef struct
{
SVzNL3DPoint center;
double radius;
}SWD_HoleInfo;
struct HSV {
double h; // 色相 (0-360)
double s; // 饱和度 (0-1)
@ -157,6 +188,20 @@ typedef struct
double jumpCornerTh_2;
}SSG_cornerParam;
typedef struct
{
double segGapTh_y; //y方向连续段门限。大于此门限为不连续
double segGapTh_z; //z方向连续段门限。大于此门限为不连续
double distScale; //计算方向角的窗口比例尺
}SSG_lineSegParam;
typedef struct
{
double minJumpZ; //z方向跳变门限
double minK; //跳变的最小斜率
SVzNLRangeD widthRange; //z方向连续段门限。大于此门限为不连续
}SSG_raisedFeatureParam;
typedef struct
{
double scale_angle; //计算方向角的窗口比例尺
@ -184,6 +229,7 @@ typedef struct
int endPtIdx;
SVzNL3DPoint startPt;
SVzNL3DPoint endPt;
double featureValue;
}SWD_segFeature;
typedef struct
@ -247,6 +293,18 @@ typedef struct
int angleChkScalePos; //仅用于加速angleCheck的速度
}SSG_featureTree;
typedef struct
{
int treeState;
int treeType;
int sLineIdx;
int eLineIdx;
double tree_value;
SSG_ROIRectD roi;
std::vector< SSG_basicFeatureGap> treeNodes;
int angleChkScalePos; //仅用于加速angleCheck的速度
}SSG_gapFeatureTree;
typedef struct
{
int treeState;
@ -483,4 +541,35 @@ typedef struct
{
SVzNL3DPoint pt1;
SVzNL3DPoint pt2;
}SWD_3DPointPair;
}SWD_3DPointPair;
typedef struct
{
int pkId;
int lineIdx;
int ptIdx;
int cptIndex; //圆周扫描上的点序
//double cornerAngle; //以点为中心的两侧弦的夹角
double R;
double angle;
double x;
double y;
double z;
}SWD_polarPt;
typedef struct
{
int cptIndex;
int L1_ptIndex;
int L2_ptIndex;
double cornerAngle;
int cornerDir;
}SWD_polarPeakInfo;
typedef struct
{
int clusterIdx;
int ptSize;
SVzNL3DRangeD roi3D;
SVzNLRect roi2D;
}SWD_clustersInfo;

View File

@ -7,6 +7,7 @@
#define SG_ERR_LABEL_INFO_ERROR -1004
#define SG_ERR_INVLD_SORTING_MODE -1005
#define SG_ERR_INVLD_Q_SCALE -1006
#define SG_ERR_ZERO_OBJECTS -1007
//BQ_workpiece
#define SX_ERR_INVLD_VTREE_NUM -2001
@ -16,6 +17,7 @@
#define SX_ERR_ZERO_CONTOUR_PT -2005
#define SX_ERR_INVLID_RPEAK_NUM -2006
#define SX_ERR_INVLID_RPEAK_PAIR -2007
#define SX_ERR_INVLID_MARK_NUM -2008
//땍綾婁혤
#define SX_ERR_INVLID_CUTTING_Z -2101
@ -23,3 +25,7 @@
//뀔관
#define SX_BAG_TRAY_EMPTY -2201
//汽车轮眉高度测量
#define SX_ERR_INVALID_ARC -2301

View File

@ -9,6 +9,14 @@
#include "VrLog.h"
#include <iomanip>
// 辅助函数:去除字符串末尾的 \r 字符(处理 Windows 格式的 CR LF 换行符)
static inline void TrimCarriageReturn(std::string& str)
{
if (!str.empty() && str.back() == '\r') {
str.pop_back();
}
}
LaserDataLoader::LaserDataLoader()
{
m_lastError.clear();
@ -57,12 +65,15 @@ int LaserDataLoader::LoadLaserScanData(const std::string& fileName,
bool bFindLineNum = true;
int nLaserPointIdx = 0;
while (std::getline(inputFile, line)) {
// 去除行末的 \r 字符(处理 Windows 格式的 CR LF 换行符)
TrimCarriageReturn(line);
if (line.find("LineNum:") == 0) {
sscanf(line.c_str(), "LineNum:%d", &lineNum);
} else if (line.find("DataType:") == 0) {
} else if (line.find("Line_") == 0) {
if(false == bFindLineNum) {
@ -513,6 +524,9 @@ int LaserDataLoader::_GetLaserType(const std::string& fileName, EVzResultDataTyp
bool bFind = false;
while (std::getline(inputFile, linedata)) {
// 去除行末的 \r 字符(处理 Windows 格式的 CR LF 换行符)
TrimCarriageReturn(linedata);
if (linedata.find("{") == 0) {
// 修复正则表达式以匹配实际数据格式
// XYZ格式: {x,y,z}-{leftX,leftY}-{rightX,rightY}

View File

@ -6,9 +6,6 @@
#include <chrono>
#include <algorithm>
// 静态成员初始化
CGlLineLaserDevice* CGlLineLaserDevice::s_pInstance = nullptr;
CGlLineLaserDevice::CGlLineLaserDevice()
: m_nDeviceId(0)
, m_bDeviceOpen(false)
@ -65,7 +62,7 @@ int CGlLineLaserDevice::OpenDevice(const char* sIP, bool bRGBD, bool bSwing, boo
memset(&ethConfig, 0, sizeof(ethConfig));
if (sIP && strlen(sIP) > 0) {
LOG_ERROR("open IP address format: %s\n", sIP);
LOG_DEBUG("open IP address format: %s\n", sIP);
// 解析IP字符串 "x.x.x.x"
int ip[4];
if (sscanf(sIP, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) {
@ -197,24 +194,10 @@ int CGlLineLaserDevice::StartDetect(VzNL_AutoOutputLaserLineExCB fCallFunc, EVzR
m_bStopDetect = false;
m_ullFrameIndex = 0;
// 设置回调实例指针
s_pInstance = this;
// 设置批处理回调
int ret = GLX8_2_SetBatchOneTimeDataHandler(m_nDeviceId, BatchDataCallback);
if (ret != 0) {
LOG_ERROR("GLX8_2_SetBatchOneTimeDataHandler failed: %d\n", ret);
return ERR_CODE(DEV_CTRL_ERR);
}
// 开始批处理采集(立即开始)
ret = GLX8_2_StartMeasureWithCallback(m_nDeviceId, 0);
if (ret != 0) {
LOG_ERROR("GLX8_2_StartMeasureWithCallback failed: %d\n", ret);
return ERR_CODE(DEV_CTRL_ERR);
}
// 启动数据采集线程(主动轮询模式)
m_bDetecting = true;
m_detectThread = std::thread(&CGlLineLaserDevice::DetectThreadFunc, this);
LOG_DEBUG("Detection started\n");
return SUCCESS;
@ -239,8 +222,12 @@ int CGlLineLaserDevice::StopDetect()
LOG_ERROR("GLX8_2_StopMeasure failed: %d\n", ret);
}
// 等待线程结束
if (m_detectThread.joinable()) {
m_detectThread.join();
}
m_bDetecting = false;
s_pInstance = nullptr;
// 通知状态变化
if (m_pStatusCallback) {
@ -253,48 +240,89 @@ int CGlLineLaserDevice::StopDetect()
return SUCCESS;
}
// 批处理数据回调(静态函数
void CGlLineLaserDevice::BatchDataCallback(const GLX8_2_STR_CALLBACK_INFO* info, const GLX8_2_Data DataObj)
// 数据采集线程函数(主动轮询模式,参考 test_deal_atch_datas
void CGlLineLaserDevice::DetectThreadFunc()
{
if (s_pInstance) {
s_pInstance->ProcessBatchData(info, DataObj);
LOG_DEBUG("Detect thread started\n");
while (!m_bStopDetect) {
// 启动批处理(参考 test_deal_atch_datas
int ret = GLX8_2_StartMeasure(m_nDeviceId, 5000); // 5秒超时
if (ret != 0) {
LOG_ERROR("GLX8_2_StartMeasure failed: %d\n", ret);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
// 等待一小段时间让设备准备好
std::this_thread::sleep_for(std::chrono::milliseconds(50));
// 获取批处理数据(参考 test_batch_datas
GetBatchData();
// 批处理完成后等待一段时间再开始下一次
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
LOG_DEBUG("Detect thread stopped\n");
}
// 处理批处理数据
void CGlLineLaserDevice::ProcessBatchData(const GLX8_2_STR_CALLBACK_INFO* info, const GLX8_2_Data DataObj)
// 获取批处理数据(参考 test_batch_datas 的流程)
void CGlLineLaserDevice::GetBatchData()
{
if (!m_pDetectCallback || m_bStopDetect) {
return;
}
GLX8_2_STR_CALLBACK_INFO info;
memset(&info, 0, sizeof(info));
int width = info->xPoints;
int batchCount = info->BatchPoints;
LOG_DEBUG("BatchPoints: %d, xPoints: %d\n", batchCount, width);
const int maxBatchLines = m_nBatchLines;
// 获取整个批次的轮廓数据(连续内存,大小为 BatchPoints * xPoints
int32_t* batchProfileData = GLX8_2_GetBatchProfilePoint(DataObj, 0);
if (!batchProfileData) {
LOG_WARNING("No profile data in batch\n");
return;
}
// 拷贝整个批次数据到本地缓存,避免回调期间数据被覆盖
size_t totalPoints = static_cast<size_t>(batchCount) * width;
// 确保缓存足够大
size_t totalPoints = static_cast<size_t>(m_nProfileWidth) * maxBatchLines;
if (m_profileBuffer.size() < totalPoints) {
m_profileBuffer.resize(totalPoints);
}
memcpy(m_profileBuffer.data(), batchProfileData, totalPoints * sizeof(int32_t));
if (m_intensityBuffer.size() < totalPoints) {
m_intensityBuffer.resize(totalPoints);
}
std::vector<uint32_t> encoderBuffer(maxBatchLines);
// 使用 GLX8_2_ReceiveDataAuto 顺序获取批处理数据
int ret = GLX8_2_ReceiveDataAuto(m_nDeviceId, &info,
m_profileBuffer.data(),
m_intensityBuffer.data(),
encoderBuffer.data());
if (ret != 0) {
LOG_WARNING("GLX8_2_ReceiveDataAuto failed: %d\n", ret);
return;
}
int batchCount = info.BatchPoints;
int width = info.xPoints;
if (batchCount <= 0 || width <= 0) {
LOG_WARNING("Invalid batch data: batchCount=%d, width=%d\n", batchCount, width);
return;
}
LOG_DEBUG("Received batch: %d lines, width: %d, startEncoder: %d\n",
batchCount, width, info.startEncoder);
// 确保位置缓存足够大
if (m_positionBuffer.size() < static_cast<size_t>(width)) {
m_positionBuffer.resize(width);
}
// 逐行处理数据并回调
// 逐行处理数据并回调转换为xyz点云数据
for (int lineIdx = 0; lineIdx < batchCount; lineIdx++) {
if (m_bStopDetect) {
break;
}
// 计算当前行在缓存中的偏移
const int32_t* lineProfile = m_profileBuffer.data() + static_cast<size_t>(lineIdx) * width;
// 转换为xyz坐标
ConvertProfileToPosition(lineProfile, width, lineIdx);
// 填充 SVzLaserLineData 结构
@ -309,32 +337,33 @@ void CGlLineLaserDevice::ProcessBatchData(const GLX8_2_STR_CALLBACK_INFO* info,
laserLineData.llFrameIdx = m_ullFrameIndex;
laserLineData.llTimeStamp = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count();
laserLineData.nEncodeNo = info->startEncoder + lineIdx;
laserLineData.nEncodeNo = encoderBuffer[lineIdx]; // 使用实际的编码器值
laserLineData.fSwingAngle = 0.0f; // 线激光没有摆动角度
laserLineData.bEndOnceScan = (lineIdx == batchCount - 1) ? VzTrue : VzFalse;
// 回调
m_pDetectCallback(m_eDataType, &laserLineData, m_pDetectCallbackParam);
// 回调给上层应用
if (m_pDetectCallback) {
m_pDetectCallback(m_eDataType, &laserLineData, m_pDetectCallbackParam);
}
m_ullFrameIndex++;
}
LOG_DEBUG("Processed %d lines, xPoints: %d\n", batchCount, width);
// 如果是最后一个批处理,通知完成
if (info->returnStatus != 0) {
StopDetect();
}
LOG_DEBUG("Processed %d lines, total frames: %llu\n", batchCount, m_ullFrameIndex);
}
// 将轮廓数据转换为位置数据
void CGlLineLaserDevice::ConvertProfileToPosition(const int32_t* profileData, int count, int lineIndex)
{
// lineIndex 参数保留用于未来扩展,当前使用 m_ullFrameIndex 计算全局偏移
(void)lineIndex;
// 确保缓存足够大
if (m_positionBuffer.size() < static_cast<size_t>(count)) {
m_positionBuffer.resize(count);
}
// 计算Y偏移基于索引)
// 计算Y偏移基于全局帧索引)
double yOffset = static_cast<double>(m_ullFrameIndex) * m_dYPitch;
// 转换每个点

View File

@ -127,10 +127,15 @@ private:
// 内部方法
/**
* @brief 线
* @brief 线 test_deal_atch_datas
*/
void DetectThreadFunc();
/**
* @brief test_batch_datas
*/
void GetBatchData();
/**
* @brief gl_linelaser_sdk SVzNL3DPosition
* @param profileData int32_t0.01um
@ -139,19 +144,6 @@ private:
* @return
*/
void ConvertProfileToPosition(const int32_t* profileData, int count, int lineIndex);
/**
* @brief
*/
static void BatchDataCallback(const GLX8_2_STR_CALLBACK_INFO* info, const GLX8_2_Data DataObj);
/**
* @brief
*/
void ProcessBatchData(const GLX8_2_STR_CALLBACK_INFO* info, const GLX8_2_Data DataObj);
// 用于回调的实例指针
static CGlLineLaserDevice* s_pInstance;
};
#endif // CGLLINELASERDEVICE_H