277 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "VrConfig.h"
#include <iostream>
#include <vector>
#include <string>
#include "VrLog.h"
#include "ConfigXmlUtils.h"
using namespace tinyxml2;
CVrConfig::CVrConfig() : m_pNotify(nullptr)
{
}
CVrConfig::~CVrConfig()
{
// 析构函数
}
int CVrConfig::LoadConfig(const std::string& filePath, ConfigResult& configResult)
{
// 使用tinyxml2库加载XML文件
XMLDocument doc;
XMLError err = doc.LoadFile(filePath.c_str());
if (err != XML_SUCCESS)
{
LOG_ERR("open config file failed: %s\n", filePath.c_str());
return LOAD_CONFIG_FILE_NOT_FOUND;
}
// 获取根元素
XMLElement* root = doc.RootElement();
if (!root || std::string(root->Name()) != "HoleDetectionConfig")
{
std::cerr << "config file format error: root element is not HoleDetectionConfig" << std::endl;
return LOAD_CONFIG_INVALID_FORMAT;
}
// 解析摄像头列表
ConfigXmlUtils::LoadCameraList(root, configResult.cameraList);
// 解析设备列表
XMLElement* devicesElement = root->FirstChildElement("Devices");
if (devicesElement)
{
XMLElement* deviceElement = devicesElement->FirstChildElement("Device");
while (deviceElement)
{
DeviceInfo device;
if (deviceElement->Attribute("name"))
device.name = deviceElement->Attribute("name");
if (deviceElement->Attribute("ip"))
device.ip = deviceElement->Attribute("ip");
configResult.deviceList.push_back(device);
deviceElement = deviceElement->NextSiblingElement("Device");
}
}
// 解析算法参数
XMLElement* algoParamsElement = root->FirstChildElement("AlgorithmParams");
if (algoParamsElement)
{
// 解析孔洞检测参数14个
XMLElement* detectionParamElement = algoParamsElement->FirstChildElement("DetectionParam");
if (detectionParamElement)
{
if (detectionParamElement->Attribute("neighborCount"))
configResult.algorithmParams.detectionParam.neighborCount = detectionParamElement->IntAttribute("neighborCount");
if (detectionParamElement->Attribute("angleThresholdPos"))
configResult.algorithmParams.detectionParam.angleThresholdPos = detectionParamElement->DoubleAttribute("angleThresholdPos");
if (detectionParamElement->Attribute("angleThresholdNeg"))
configResult.algorithmParams.detectionParam.angleThresholdNeg = detectionParamElement->DoubleAttribute("angleThresholdNeg");
if (detectionParamElement->Attribute("minPitDepth"))
configResult.algorithmParams.detectionParam.minPitDepth = detectionParamElement->DoubleAttribute("minPitDepth");
if (detectionParamElement->Attribute("minRadius"))
configResult.algorithmParams.detectionParam.minRadius = detectionParamElement->DoubleAttribute("minRadius");
if (detectionParamElement->Attribute("maxRadius"))
configResult.algorithmParams.detectionParam.maxRadius = detectionParamElement->DoubleAttribute("maxRadius");
if (detectionParamElement->Attribute("expansionSize1"))
configResult.algorithmParams.detectionParam.expansionSize1 = detectionParamElement->IntAttribute("expansionSize1");
if (detectionParamElement->Attribute("expansionSize2"))
configResult.algorithmParams.detectionParam.expansionSize2 = detectionParamElement->IntAttribute("expansionSize2");
if (detectionParamElement->Attribute("minVTransitionPoints"))
configResult.algorithmParams.detectionParam.minVTransitionPoints = detectionParamElement->IntAttribute("minVTransitionPoints");
if (detectionParamElement->Attribute("edgeBoundaryFilterDist"))
configResult.algorithmParams.detectionParam.edgeBoundaryFilterDist = detectionParamElement->DoubleAttribute("edgeBoundaryFilterDist");
}
// 解析孔洞过滤参数
XMLElement* filterParamElement = algoParamsElement->FirstChildElement("FilterParam");
if (filterParamElement)
{
if (filterParamElement->Attribute("maxEccentricity"))
configResult.algorithmParams.filterParam.maxEccentricity = filterParamElement->DoubleAttribute("maxEccentricity");
if (filterParamElement->Attribute("minAngularCoverage"))
configResult.algorithmParams.filterParam.minAngularCoverage = filterParamElement->DoubleAttribute("minAngularCoverage");
if (filterParamElement->Attribute("maxRadiusFitRatio"))
configResult.algorithmParams.filterParam.maxRadiusFitRatio = filterParamElement->DoubleAttribute("maxRadiusFitRatio");
if (filterParamElement->Attribute("minQualityScore"))
configResult.algorithmParams.filterParam.minQualityScore = filterParamElement->DoubleAttribute("minQualityScore");
if (filterParamElement->Attribute("maxPlaneResidual"))
configResult.algorithmParams.filterParam.maxPlaneResidual = filterParamElement->DoubleAttribute("maxPlaneResidual");
if (filterParamElement->Attribute("maxAngularGap"))
configResult.algorithmParams.filterParam.maxAngularGap = filterParamElement->DoubleAttribute("maxAngularGap");
if (filterParamElement->Attribute("minInlierRatio"))
configResult.algorithmParams.filterParam.minInlierRatio = filterParamElement->DoubleAttribute("minInlierRatio");
if (filterParamElement->Attribute("minHoleDepth"))
configResult.algorithmParams.filterParam.minHoleDepth = filterParamElement->DoubleAttribute("minHoleDepth");
}
// 解析排序模式
XMLElement* sortModeElement = algoParamsElement->FirstChildElement("SortMode");
if (sortModeElement)
{
if (sortModeElement->Attribute("value"))
configResult.algorithmParams.sortMode = sortModeElement->IntAttribute("value");
}
// 解析多相机平面校准参数
ConfigXmlUtils::LoadPlaneCalibParams(algoParamsElement, configResult.algorithmParams.planeCalibParam);
}
// 解析调试参数
ConfigXmlUtils::LoadDebugParam(root, configResult.debugParam);
// 解析串口配置
ConfigXmlUtils::LoadSerialConfig(root, configResult.serialConfig);
// 解析手眼标定矩阵列表(支持多相机)
ConfigXmlUtils::LoadHandEyeCalibMatrixs(root, configResult.handEyeCalibMatrixList);
// 解析TCP服务端配置
XMLElement* tcpServerConfigElement = root->FirstChildElement("TcpServerConfig");
if (tcpServerConfigElement)
{
// 解析TCP协议端口
if (tcpServerConfigElement->Attribute("tcpServerPort"))
configResult.plcRobotServerConfig.tcpServerPort = tcpServerConfigElement->IntAttribute("tcpServerPort");
else
configResult.plcRobotServerConfig.tcpServerPort = 7800; // 默认7800
// 解析姿态输出顺序配置
if (tcpServerConfigElement->Attribute("poseOutputOrder"))
configResult.plcRobotServerConfig.poseOutputOrder = tcpServerConfigElement->IntAttribute("poseOutputOrder");
else
configResult.plcRobotServerConfig.poseOutputOrder = POSE_ORDER_RPY; // 默认RPY
// 解析方向向量反向配置
if (tcpServerConfigElement->Attribute("dirVectorInvert"))
configResult.plcRobotServerConfig.dirVectorInvert = tcpServerConfigElement->IntAttribute("dirVectorInvert");
else
configResult.plcRobotServerConfig.dirVectorInvert = DIR_INVERT_YZ; // 默认YZ反向
}
return LOAD_CONFIG_SUCCESS;
}
bool CVrConfig::SaveConfig(const std::string& filePath, ConfigResult& configResult)
{
// 创建XML文档
XMLDocument doc;
// 添加声明
XMLDeclaration* declaration = doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");
doc.InsertFirstChild(declaration);
// 创建根元素
XMLElement* root = doc.NewElement("HoleDetectionConfig");
doc.InsertEndChild(root);
// 添加摄像头列表
ConfigXmlUtils::SaveCameraList(doc, root, configResult.cameraList);
// 添加设备列表
XMLElement* devicesElement = doc.NewElement("Devices");
root->InsertEndChild(devicesElement);
for (const auto& device : configResult.deviceList)
{
XMLElement* deviceElement = doc.NewElement("Device");
deviceElement->SetAttribute("name", device.name.c_str());
deviceElement->SetAttribute("ip", device.ip.c_str());
devicesElement->InsertEndChild(deviceElement);
}
// 添加算法参数
XMLElement* algoParamsElement = doc.NewElement("AlgorithmParams");
root->InsertEndChild(algoParamsElement);
// 添加孔洞检测参数
XMLElement* detectionParamElement = doc.NewElement("DetectionParam");
detectionParamElement->SetAttribute("neighborCount", configResult.algorithmParams.detectionParam.neighborCount);
detectionParamElement->SetAttribute("angleThresholdPos", configResult.algorithmParams.detectionParam.angleThresholdPos);
detectionParamElement->SetAttribute("angleThresholdNeg", configResult.algorithmParams.detectionParam.angleThresholdNeg);
detectionParamElement->SetAttribute("minPitDepth", configResult.algorithmParams.detectionParam.minPitDepth);
detectionParamElement->SetAttribute("minRadius", configResult.algorithmParams.detectionParam.minRadius);
detectionParamElement->SetAttribute("maxRadius", configResult.algorithmParams.detectionParam.maxRadius);
detectionParamElement->SetAttribute("expansionSize1", configResult.algorithmParams.detectionParam.expansionSize1);
detectionParamElement->SetAttribute("expansionSize2", configResult.algorithmParams.detectionParam.expansionSize2);
detectionParamElement->SetAttribute("minVTransitionPoints", configResult.algorithmParams.detectionParam.minVTransitionPoints);
detectionParamElement->SetAttribute("edgeBoundaryFilterDist", configResult.algorithmParams.detectionParam.edgeBoundaryFilterDist);
algoParamsElement->InsertEndChild(detectionParamElement);
// 添加孔洞过滤参数
XMLElement* filterParamElement = doc.NewElement("FilterParam");
filterParamElement->SetAttribute("maxEccentricity", configResult.algorithmParams.filterParam.maxEccentricity);
filterParamElement->SetAttribute("minAngularCoverage", configResult.algorithmParams.filterParam.minAngularCoverage);
filterParamElement->SetAttribute("maxRadiusFitRatio", configResult.algorithmParams.filterParam.maxRadiusFitRatio);
filterParamElement->SetAttribute("minQualityScore", configResult.algorithmParams.filterParam.minQualityScore);
filterParamElement->SetAttribute("maxPlaneResidual", configResult.algorithmParams.filterParam.maxPlaneResidual);
filterParamElement->SetAttribute("maxAngularGap", configResult.algorithmParams.filterParam.maxAngularGap);
filterParamElement->SetAttribute("minInlierRatio", configResult.algorithmParams.filterParam.minInlierRatio);
filterParamElement->SetAttribute("minHoleDepth", configResult.algorithmParams.filterParam.minHoleDepth);
algoParamsElement->InsertEndChild(filterParamElement);
// 添加排序模式
XMLElement* sortModeElement = doc.NewElement("SortMode");
sortModeElement->SetAttribute("value", configResult.algorithmParams.sortMode);
algoParamsElement->InsertEndChild(sortModeElement);
// 添加多相机平面校准参数
ConfigXmlUtils::SavePlaneCalibParams(doc, algoParamsElement, configResult.algorithmParams.planeCalibParam);
// 添加调试参数
ConfigXmlUtils::SaveDebugParam(doc, root, configResult.debugParam);
// 添加串口配置
ConfigXmlUtils::SaveSerialConfig(doc, root, configResult.serialConfig);
// 添加手眼标定矩阵列表(支持多相机)
ConfigXmlUtils::SaveHandEyeCalibMatrixs(doc, root, configResult.handEyeCalibMatrixList);
// 添加TCP服务端配置
XMLElement* tcpServerConfigElement = doc.NewElement("TcpServerConfig");
tcpServerConfigElement->SetAttribute("tcpServerPort", configResult.plcRobotServerConfig.tcpServerPort);
// 保存姿态输出顺序配置
tcpServerConfigElement->SetAttribute("poseOutputOrder", configResult.plcRobotServerConfig.poseOutputOrder);
// 保存方向向量反向配置
tcpServerConfigElement->SetAttribute("dirVectorInvert", configResult.plcRobotServerConfig.dirVectorInvert);
root->InsertEndChild(tcpServerConfigElement);
// 保存到文件
XMLError err = doc.SaveFile(filePath.c_str());
if (err != XML_SUCCESS)
{
std::cerr << "无法保存配置文件: " << filePath << std::endl;
return false;
}
// 触发配置改变通知
if (m_pNotify)
{
m_pNotify->OnConfigChanged(configResult);
}
return true;
}
// 设置配置改变通知回调
void CVrConfig::SetConfigChangeNotify(IVrConfigChangeNotify* notify)
{
m_pNotify = notify;
}
/**
* @brief 创建实例
* @return 实例
*/
bool IVrConfig::CreateInstance(IVrConfig** ppVrConfig)
{
*ppVrConfig = new CVrConfig();
return *ppVrConfig != nullptr;
}