2026-07-14 17:14:55 +08:00

361 lines
16 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;
namespace {
void LoadWorkpieceProfileParams(
XMLElement* parentElement,
VrWorkpieceAlgorithmProfile& profile)
{
if (!parentElement) {
return;
}
XMLElement* workpieceHoleParamElement = parentElement->FirstChildElement("WorkpieceHoleParam");
if (workpieceHoleParamElement)
{
if (workpieceHoleParamElement->Attribute("workpieceType"))
profile.workpieceHoleParam.workpieceType = workpieceHoleParamElement->IntAttribute("workpieceType");
if (workpieceHoleParamElement->Attribute("holeDiameter"))
profile.workpieceHoleParam.holeDiameter = workpieceHoleParamElement->DoubleAttribute("holeDiameter");
if (workpieceHoleParamElement->Attribute("bigHoleDiameter"))
profile.workpieceHoleParam.bigHoleDiameter = workpieceHoleParamElement->DoubleAttribute("bigHoleDiameter");
if (workpieceHoleParamElement->Attribute("holeDist_L"))
profile.workpieceHoleParam.holeDist_L = workpieceHoleParamElement->DoubleAttribute("holeDist_L");
if (workpieceHoleParamElement->Attribute("holeDist_W"))
profile.workpieceHoleParam.holeDist_W = workpieceHoleParamElement->DoubleAttribute("holeDist_W");
if (workpieceHoleParamElement->Attribute("xLen"))
profile.workpieceHoleParam.xLen = workpieceHoleParamElement->DoubleAttribute("xLen");
if (workpieceHoleParamElement->Attribute("yLen"))
profile.workpieceHoleParam.yLen = workpieceHoleParamElement->DoubleAttribute("yLen");
if (workpieceHoleParamElement->Attribute("H"))
profile.workpieceHoleParam.H = workpieceHoleParamElement->DoubleAttribute("H");
}
XMLElement* filterParamElement = parentElement->FirstChildElement("FilterParam");
if (filterParamElement)
{
if (filterParamElement->Attribute("continuityTh"))
profile.filterParam.continuityTh = filterParamElement->DoubleAttribute("continuityTh");
if (filterParamElement->Attribute("outlierTh"))
profile.filterParam.outlierTh = filterParamElement->DoubleAttribute("outlierTh");
}
XMLElement* lineSegParamElement = parentElement->FirstChildElement("LineSegParam");
if (lineSegParamElement)
{
if (lineSegParamElement->Attribute("distScale"))
profile.lineSegParam.distScale = lineSegParamElement->DoubleAttribute("distScale");
if (lineSegParamElement->Attribute("segGapTh_y"))
profile.lineSegParam.segGapTh_y = lineSegParamElement->DoubleAttribute("segGapTh_y");
if (lineSegParamElement->Attribute("segGapTh_z"))
profile.lineSegParam.segGapTh_z = lineSegParamElement->DoubleAttribute("segGapTh_z");
}
XMLElement* growParamElement = parentElement->FirstChildElement("GrowParam");
if (growParamElement)
{
if (growParamElement->Attribute("maxLineSkipNum"))
profile.growParam.maxLineSkipNum = growParamElement->IntAttribute("maxLineSkipNum");
if (growParamElement->Attribute("yDeviation_max"))
profile.growParam.yDeviation_max = growParamElement->DoubleAttribute("yDeviation_max");
if (growParamElement->Attribute("maxSkipDistance"))
profile.growParam.maxSkipDistance = growParamElement->DoubleAttribute("maxSkipDistance");
if (growParamElement->Attribute("zDeviation_max"))
profile.growParam.zDeviation_max = growParamElement->DoubleAttribute("zDeviation_max");
if (growParamElement->Attribute("minLTypeTreeLen"))
profile.growParam.minLTypeTreeLen = growParamElement->DoubleAttribute("minLTypeTreeLen");
if (growParamElement->Attribute("minVTypeTreeLen"))
profile.growParam.minVTypeTreeLen = growParamElement->DoubleAttribute("minVTypeTreeLen");
}
}
void SaveWorkpieceProfileParams(
XMLDocument& doc,
XMLElement* algoParamsElement,
const VrWorkpieceAlgorithmProfile& profile)
{
XMLElement* profileElement = doc.NewElement("WorkpieceParamGroup");
profileElement->SetAttribute("workpieceNumber", profile.workpieceNumber);
algoParamsElement->InsertEndChild(profileElement);
XMLElement* workpieceHoleParamElement = doc.NewElement("WorkpieceHoleParam");
workpieceHoleParamElement->SetAttribute("workpieceType", profile.workpieceHoleParam.workpieceType);
workpieceHoleParamElement->SetAttribute("holeDiameter", profile.workpieceHoleParam.holeDiameter);
workpieceHoleParamElement->SetAttribute("bigHoleDiameter", profile.workpieceHoleParam.bigHoleDiameter);
workpieceHoleParamElement->SetAttribute("holeDist_L", profile.workpieceHoleParam.holeDist_L);
workpieceHoleParamElement->SetAttribute("holeDist_W", profile.workpieceHoleParam.holeDist_W);
workpieceHoleParamElement->SetAttribute("xLen", profile.workpieceHoleParam.xLen);
workpieceHoleParamElement->SetAttribute("yLen", profile.workpieceHoleParam.yLen);
workpieceHoleParamElement->SetAttribute("H", profile.workpieceHoleParam.H);
profileElement->InsertEndChild(workpieceHoleParamElement);
XMLElement* filterParamElement = doc.NewElement("FilterParam");
filterParamElement->SetAttribute("continuityTh", profile.filterParam.continuityTh);
filterParamElement->SetAttribute("outlierTh", profile.filterParam.outlierTh);
profileElement->InsertEndChild(filterParamElement);
XMLElement* lineSegParamElement = doc.NewElement("LineSegParam");
lineSegParamElement->SetAttribute("distScale", profile.lineSegParam.distScale);
lineSegParamElement->SetAttribute("segGapTh_y", profile.lineSegParam.segGapTh_y);
lineSegParamElement->SetAttribute("segGapTh_z", profile.lineSegParam.segGapTh_z);
profileElement->InsertEndChild(lineSegParamElement);
XMLElement* growParamElement = doc.NewElement("GrowParam");
growParamElement->SetAttribute("maxLineSkipNum", profile.growParam.maxLineSkipNum);
growParamElement->SetAttribute("yDeviation_max", profile.growParam.yDeviation_max);
growParamElement->SetAttribute("maxSkipDistance", profile.growParam.maxSkipDistance);
growParamElement->SetAttribute("zDeviation_max", profile.growParam.zDeviation_max);
growParamElement->SetAttribute("minLTypeTreeLen", profile.growParam.minLTypeTreeLen);
growParamElement->SetAttribute("minVTypeTreeLen", profile.growParam.minVTypeTreeLen);
profileElement->InsertEndChild(growParamElement);
}
} // namespace
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()) != "WorkpieceHoleConfig")
{
std::cerr << "config file format error: root element is not WorkpieceHoleConfig" << 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");
}
}
// 每次加载都从完整的工件默认参数组开始,避免复用对象时残留旧数据。
configResult.algorithmParams = VrAlgorithmParams();
// 解析算法参数
XMLElement* algoParamsElement = root->FirstChildElement("AlgorithmParams");
if (algoParamsElement)
{
XMLElement* profileElement = algoParamsElement->FirstChildElement("WorkpieceParamGroup");
if (profileElement) {
while (profileElement) {
const int workpieceNumber = profileElement->IntAttribute("workpieceNumber", 0);
VrWorkpieceAlgorithmProfile* workpieceProfile =
configResult.algorithmParams.FindWorkpieceProfile(workpieceNumber);
if (workpieceProfile) {
LoadWorkpieceProfileParams(profileElement, *workpieceProfile);
}
profileElement = profileElement->NextSiblingElement("WorkpieceParamGroup");
}
} else {
// 兼容旧版单套参数旧参数归入工件1其余工件保留 test 默认值。
VrWorkpieceAlgorithmProfile* workpieceProfile =
configResult.algorithmParams.FindWorkpieceProfile(1);
if (workpieceProfile) {
LoadWorkpieceProfileParams(algoParamsElement, *workpieceProfile);
}
}
// 解析多相机平面校准参数
ConfigXmlUtils::LoadPlaneCalibParams(algoParamsElement, configResult.algorithmParams.planeCalibParam);
}
// 解析调试参数
ConfigXmlUtils::LoadDebugParam(root, configResult.debugParam);
// 解析串口配置
ConfigXmlUtils::LoadSerialConfig(root, configResult.serialConfig);
// 解析手眼标定矩阵列表(支持多相机)
ConfigXmlUtils::LoadHandEyeCalibMatrixs(root, configResult.handEyeCalibMatrixList);
// 解析TCP服务端配置PLC和机械臂
XMLElement* tcpServerConfigElement = root->FirstChildElement("TcpServerConfig");
if (tcpServerConfigElement)
{
if (tcpServerConfigElement->Attribute("plcServerIp"))
configResult.plcRobotServerConfig.plcServerIp = tcpServerConfigElement->Attribute("plcServerIp");
if (tcpServerConfigElement->Attribute("plcServerPort"))
configResult.plcRobotServerConfig.plcServerPort = tcpServerConfigElement->IntAttribute("plcServerPort");
if (tcpServerConfigElement->Attribute("robotServerIp"))
configResult.plcRobotServerConfig.robotServerIp = tcpServerConfigElement->Attribute("robotServerIp");
if (tcpServerConfigElement->Attribute("robotServerPort"))
configResult.plcRobotServerConfig.robotServerPort = tcpServerConfigElement->IntAttribute("robotServerPort");
// 解析PLC寄存器地址配置
if (tcpServerConfigElement->Attribute("addrPhotoRequest"))
configResult.plcRobotServerConfig.registerConfig.addrPhotoRequest = tcpServerConfigElement->IntAttribute("addrPhotoRequest");
if (tcpServerConfigElement->Attribute("addrDataComplete"))
configResult.plcRobotServerConfig.registerConfig.addrDataComplete = tcpServerConfigElement->IntAttribute("addrDataComplete");
if (tcpServerConfigElement->Attribute("addrCoordDataStart"))
configResult.plcRobotServerConfig.registerConfig.addrCoordDataStart = tcpServerConfigElement->IntAttribute("addrCoordDataStart");
// 解析姿态输出顺序配置
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反向兼容原有行为
// 解析数据字节序配置
if (tcpServerConfigElement->Attribute("byteOrder"))
configResult.plcRobotServerConfig.byteOrder = tcpServerConfigElement->IntAttribute("byteOrder");
else
configResult.plcRobotServerConfig.byteOrder = BYTE_ORDER_BIG_ENDIAN; // 默认大端序
}
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("WorkpieceHoleConfig");
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);
// 每个工件保存一套独立算法参数。
for (int workpieceNumber = 1; workpieceNumber <= 5; ++workpieceNumber) {
const VrWorkpieceAlgorithmProfile* workpieceProfile =
configResult.algorithmParams.FindWorkpieceProfile(workpieceNumber);
if (workpieceProfile) {
SaveWorkpieceProfileParams(doc, algoParamsElement, *workpieceProfile);
}
}
// 添加多相机平面校准参数
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服务端配置PLC和机械臂
XMLElement* tcpServerConfigElement = doc.NewElement("TcpServerConfig");
tcpServerConfigElement->SetAttribute("plcServerIp", configResult.plcRobotServerConfig.plcServerIp.c_str());
tcpServerConfigElement->SetAttribute("plcServerPort", configResult.plcRobotServerConfig.plcServerPort);
tcpServerConfigElement->SetAttribute("robotServerIp", configResult.plcRobotServerConfig.robotServerIp.c_str());
tcpServerConfigElement->SetAttribute("robotServerPort", configResult.plcRobotServerConfig.robotServerPort);
// 保存PLC寄存器地址配置
tcpServerConfigElement->SetAttribute("addrPhotoRequest", configResult.plcRobotServerConfig.registerConfig.addrPhotoRequest);
tcpServerConfigElement->SetAttribute("addrDataComplete", configResult.plcRobotServerConfig.registerConfig.addrDataComplete);
tcpServerConfigElement->SetAttribute("addrCoordDataStart", configResult.plcRobotServerConfig.registerConfig.addrCoordDataStart);
// 保存姿态输出顺序配置
tcpServerConfigElement->SetAttribute("poseOutputOrder", configResult.plcRobotServerConfig.poseOutputOrder);
// 保存方向向量反向配置
tcpServerConfigElement->SetAttribute("dirVectorInvert", configResult.plcRobotServerConfig.dirVectorInvert);
// 保存数据字节序配置
tcpServerConfigElement->SetAttribute("byteOrder", configResult.plcRobotServerConfig.byteOrder);
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;
}