551 lines
28 KiB
C++
Raw Normal View History

2026-08-04 14:23:07 +08:00
#include "VrConfig.h"
#include <iostream>
#include <vector>
#include <string>
#include "VrLog.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()) != "StatorWorkpiecePositionConfig")
{
std::cerr << "config file format error: root element is not StatorWorkpiecePositionConfig" << std::endl;
return LOAD_CONFIG_INVALID_FORMAT;
}
// 解析摄像头列表
XMLElement* camerasElement = root->FirstChildElement("Cameras");
if (camerasElement)
{
XMLElement* cameraElement = camerasElement->FirstChildElement("Camera");
while (cameraElement)
{
DeviceInfo camera;
if (cameraElement->Attribute("name"))
camera.name = cameraElement->Attribute("name");
if (cameraElement->Attribute("ip"))
camera.ip = cameraElement->Attribute("ip");
configResult.cameraList.push_back(camera);
cameraElement = cameraElement->NextSiblingElement("Camera");
}
}
// 解析设备列表
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)
{
// 解析工具姿态与目标点补偿参数(与 WorkpieceHole 配置方式一致)
XMLElement* toolParamElement = algoParamsElement->FirstChildElement("ToolParam");
if (toolParamElement)
{
if (toolParamElement->Attribute("eulerOrder"))
configResult.algorithmParams.toolParam.eulerOrder = toolParamElement->IntAttribute("eulerOrder");
if (toolParamElement->Attribute("rotX"))
configResult.algorithmParams.toolParam.rotX = toolParamElement->DoubleAttribute("rotX");
if (toolParamElement->Attribute("rotY"))
configResult.algorithmParams.toolParam.rotY = toolParamElement->DoubleAttribute("rotY");
if (toolParamElement->Attribute("rotZ"))
configResult.algorithmParams.toolParam.rotZ = toolParamElement->DoubleAttribute("rotZ");
if (toolParamElement->Attribute("offsetX"))
configResult.algorithmParams.toolParam.offsetX = toolParamElement->DoubleAttribute("offsetX");
if (toolParamElement->Attribute("offsetY"))
configResult.algorithmParams.toolParam.offsetY = toolParamElement->DoubleAttribute("offsetY");
if (toolParamElement->Attribute("offsetZ"))
configResult.algorithmParams.toolParam.offsetZ = toolParamElement->DoubleAttribute("offsetZ");
}
XMLElement* modelParamElement = algoParamsElement->FirstChildElement("WorkpieceModelParam");
if (modelParamElement)
{
VrWorkpieceModelParam& modelParam = configResult.algorithmParams.modelParam;
if (modelParamElement->Attribute("minimumScore"))
modelParam.minimumScore = modelParamElement->DoubleAttribute("minimumScore");
if (modelParamElement->Attribute("class0WorkpieceType"))
modelParam.class0WorkpieceType = modelParamElement->IntAttribute("class0WorkpieceType");
if (modelParamElement->Attribute("class1WorkpieceType"))
modelParam.class1WorkpieceType = modelParamElement->IntAttribute("class1WorkpieceType");
if (modelParamElement->Attribute("class2WorkpieceType"))
modelParam.class2WorkpieceType = modelParamElement->IntAttribute("class2WorkpieceType");
}
XMLElement* fullImageCaptureElement = algoParamsElement->FirstChildElement("FullImageCaptureParam");
if (fullImageCaptureElement)
{
VrFullImageCaptureParam& captureParam = configResult.algorithmParams.fullImageCaptureParam;
if (fullImageCaptureElement->Attribute("exposure"))
captureParam.exposure = fullImageCaptureElement->UnsignedAttribute("exposure");
if (fullImageCaptureElement->Attribute("gain"))
captureParam.gain = fullImageCaptureElement->UnsignedAttribute("gain");
}
XMLElement* binParamElement = algoParamsElement->FirstChildElement("BinParam");
if (binParamElement)
{
VrBinParam& binParam = configResult.algorithmParams.binParam;
if (binParamElement->Attribute("useConfiguredBin"))
binParam.useConfiguredBin = binParamElement->BoolAttribute("useConfiguredBin");
if (binParamElement->Attribute("binHeight"))
binParam.binHeight = binParamElement->DoubleAttribute("binHeight");
if (binParamElement->Attribute("length"))
binParam.length = binParamElement->DoubleAttribute("length");
if (binParamElement->Attribute("width"))
binParam.width = binParamElement->DoubleAttribute("width");
if (binParamElement->Attribute("binTopZ"))
binParam.binTopZ = binParamElement->DoubleAttribute("binTopZ");
auto readVec3 = [binParamElement](const char* prefix, double values[3]) {
char attrName[64];
for (int i = 0; i < 3; ++i) {
sprintf(attrName, "%s%d", prefix, i);
if (binParamElement->Attribute(attrName))
values[i] = binParamElement->DoubleAttribute(attrName);
}
};
readVec3("center", binParam.center);
readVec3("bottomNormal", binParam.bottomNormal);
readVec3("xDir", binParam.xDir);
readVec3("yDir", binParam.yDir);
for (int vertex = 0; vertex < 4; ++vertex) {
char attrName[64];
for (int axis = 0; axis < 3; ++axis) {
sprintf(attrName, "minRectVertex%d_%d", vertex, axis);
if (binParamElement->Attribute(attrName))
binParam.minRectVertex[vertex][axis] =
binParamElement->DoubleAttribute(attrName);
}
}
}
XMLElement* rotorCoreParamElement = algoParamsElement->FirstChildElement("RotorCoreParam");
if (rotorCoreParamElement)
{
VrRotorCoreParam& rotorParam = configResult.algorithmParams.rotorCoreParam;
if (rotorCoreParamElement->Attribute("radius"))
rotorParam.radius = rotorCoreParamElement->DoubleAttribute("radius");
if (rotorCoreParamElement->Attribute("height"))
rotorParam.height = rotorCoreParamElement->DoubleAttribute("height");
}
// 解析多相机平面校准参数
XMLElement* planeCalibParamsElement = algoParamsElement->FirstChildElement("PlaneCalibParams");
if (planeCalibParamsElement)
{
XMLElement* cameraCalibParamElement = planeCalibParamsElement->FirstChildElement("CameraCalibParam");
while (cameraCalibParamElement)
{
VrCameraPlaneCalibParam cameraParam;
// 读取相机基础信息
if (cameraCalibParamElement->Attribute("cameraIndex"))
cameraParam.cameraIndex = cameraCalibParamElement->IntAttribute("cameraIndex");
if (cameraCalibParamElement->Attribute("cameraName"))
cameraParam.cameraName = cameraCalibParamElement->Attribute("cameraName");
if (cameraCalibParamElement->Attribute("isCalibrated"))
cameraParam.isCalibrated = cameraCalibParamElement->BoolAttribute("isCalibrated");
if (cameraCalibParamElement->Attribute("planeHeight"))
cameraParam.planeHeight = cameraCalibParamElement->DoubleAttribute("planeHeight");
// 读取旋转矩阵planeCalib[9] (3x3矩阵)
if (cameraCalibParamElement->Attribute("planeCalib_00"))
cameraParam.planeCalib[0] = cameraCalibParamElement->DoubleAttribute("planeCalib_00");
if (cameraCalibParamElement->Attribute("planeCalib_01"))
cameraParam.planeCalib[1] = cameraCalibParamElement->DoubleAttribute("planeCalib_01");
if (cameraCalibParamElement->Attribute("planeCalib_02"))
cameraParam.planeCalib[2] = cameraCalibParamElement->DoubleAttribute("planeCalib_02");
if (cameraCalibParamElement->Attribute("planeCalib_10"))
cameraParam.planeCalib[3] = cameraCalibParamElement->DoubleAttribute("planeCalib_10");
if (cameraCalibParamElement->Attribute("planeCalib_11"))
cameraParam.planeCalib[4] = cameraCalibParamElement->DoubleAttribute("planeCalib_11");
if (cameraCalibParamElement->Attribute("planeCalib_12"))
cameraParam.planeCalib[5] = cameraCalibParamElement->DoubleAttribute("planeCalib_12");
if (cameraCalibParamElement->Attribute("planeCalib_20"))
cameraParam.planeCalib[6] = cameraCalibParamElement->DoubleAttribute("planeCalib_20");
if (cameraCalibParamElement->Attribute("planeCalib_21"))
cameraParam.planeCalib[7] = cameraCalibParamElement->DoubleAttribute("planeCalib_21");
if (cameraCalibParamElement->Attribute("planeCalib_22"))
cameraParam.planeCalib[8] = cameraCalibParamElement->DoubleAttribute("planeCalib_22");
// 读取逆旋转矩阵invRMatrix[9] (3x3矩阵)
if (cameraCalibParamElement->Attribute("invRMatrix_00"))
cameraParam.invRMatrix[0] = cameraCalibParamElement->DoubleAttribute("invRMatrix_00");
if (cameraCalibParamElement->Attribute("invRMatrix_01"))
cameraParam.invRMatrix[1] = cameraCalibParamElement->DoubleAttribute("invRMatrix_01");
if (cameraCalibParamElement->Attribute("invRMatrix_02"))
cameraParam.invRMatrix[2] = cameraCalibParamElement->DoubleAttribute("invRMatrix_02");
if (cameraCalibParamElement->Attribute("invRMatrix_10"))
cameraParam.invRMatrix[3] = cameraCalibParamElement->DoubleAttribute("invRMatrix_10");
if (cameraCalibParamElement->Attribute("invRMatrix_11"))
cameraParam.invRMatrix[4] = cameraCalibParamElement->DoubleAttribute("invRMatrix_11");
if (cameraCalibParamElement->Attribute("invRMatrix_12"))
cameraParam.invRMatrix[5] = cameraCalibParamElement->DoubleAttribute("invRMatrix_12");
if (cameraCalibParamElement->Attribute("invRMatrix_20"))
cameraParam.invRMatrix[6] = cameraCalibParamElement->DoubleAttribute("invRMatrix_20");
if (cameraCalibParamElement->Attribute("invRMatrix_21"))
cameraParam.invRMatrix[7] = cameraCalibParamElement->DoubleAttribute("invRMatrix_21");
if (cameraCalibParamElement->Attribute("invRMatrix_22"))
cameraParam.invRMatrix[8] = cameraCalibParamElement->DoubleAttribute("invRMatrix_22");
// 添加到结果中
configResult.algorithmParams.planeCalibParam.cameraCalibParams.push_back(cameraParam);
// 移动到下一个相机配置
cameraCalibParamElement = cameraCalibParamElement->NextSiblingElement("CameraCalibParam");
}
}
}
// 解析调试参数在AlgorithmParams外面
XMLElement* debugParamElement = root->FirstChildElement("DebugParam");
if (debugParamElement)
{
if (debugParamElement->Attribute("enableDebug"))
configResult.debugParam.enableDebug = debugParamElement->BoolAttribute("enableDebug");
if (debugParamElement->Attribute("savePointCloud"))
configResult.debugParam.savePointCloud = debugParamElement->BoolAttribute("savePointCloud");
if (debugParamElement->Attribute("saveDebugImage"))
configResult.debugParam.saveDebugImage = debugParamElement->BoolAttribute("saveDebugImage");
if (debugParamElement->Attribute("printDetailLog"))
configResult.debugParam.printDetailLog = debugParamElement->BoolAttribute("printDetailLog");
if (debugParamElement->Attribute("debugOutputPath"))
configResult.debugParam.debugOutputPath = debugParamElement->Attribute("debugOutputPath");
}
// 解析串口配置
XMLElement* serialConfigElement = root->FirstChildElement("SerialConfig");
if (serialConfigElement)
{
if (serialConfigElement->Attribute("portName"))
configResult.serialConfig.portName = serialConfigElement->Attribute("portName");
if (serialConfigElement->Attribute("baudRate"))
configResult.serialConfig.baudRate = serialConfigElement->IntAttribute("baudRate");
if (serialConfigElement->Attribute("dataBits"))
configResult.serialConfig.dataBits = serialConfigElement->IntAttribute("dataBits");
if (serialConfigElement->Attribute("stopBits"))
configResult.serialConfig.stopBits = serialConfigElement->IntAttribute("stopBits");
if (serialConfigElement->Attribute("parity"))
configResult.serialConfig.parity = serialConfigElement->IntAttribute("parity");
if (serialConfigElement->Attribute("flowControl"))
configResult.serialConfig.flowControl = serialConfigElement->IntAttribute("flowControl");
if (serialConfigElement->Attribute("enabled"))
configResult.serialConfig.enabled = serialConfigElement->BoolAttribute("enabled");
}
// 解析手眼标定矩阵
XMLElement* handEyeElement = root->FirstChildElement("HandEyeCalibMatrix");
if (handEyeElement)
{
for (int i = 0; i < 16; i++)
{
char attrName[32];
sprintf(attrName, "m%d", i);
if (handEyeElement->Attribute(attrName))
configResult.handEyeCalibMatrix.matrix[i] = handEyeElement->DoubleAttribute(attrName);
}
// 读取旋转顺序如果不存在则使用默认值11外旋ZYX
if (handEyeElement->Attribute("eulerOrder"))
configResult.handEyeCalibMatrix.eulerOrder = handEyeElement->IntAttribute("eulerOrder");
else
configResult.handEyeCalibMatrix.eulerOrder = 11; // 默认外旋ZYX
}
// 解析 TCP/IP 文本服务端端口和 Modbus 寄存器配置
XMLElement* tcpServerConfigElement = root->FirstChildElement("TcpServerConfig");
if (tcpServerConfigElement)
{
if (tcpServerConfigElement->Attribute("robotServerPort"))
configResult.plcRobotServerConfig.robotServerPort = tcpServerConfigElement->IntAttribute("robotServerPort");
// 解析Modbus寄存器地址配置
if (tcpServerConfigElement->Attribute("addrTrigger"))
configResult.plcRobotServerConfig.registerConfig.addrTrigger = tcpServerConfigElement->IntAttribute("addrTrigger");
if (tcpServerConfigElement->Attribute("addrWorkStatus"))
configResult.plcRobotServerConfig.registerConfig.addrWorkStatus = tcpServerConfigElement->IntAttribute("addrWorkStatus");
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("StatorWorkpiecePositionConfig");
doc.InsertEndChild(root);
// 添加摄像头列表
XMLElement* camerasElement = doc.NewElement("Cameras");
root->InsertEndChild(camerasElement);
for (const auto& camera : configResult.cameraList)
{
XMLElement* cameraElement = doc.NewElement("Camera");
cameraElement->SetAttribute("name", camera.name.c_str());
cameraElement->SetAttribute("ip", camera.ip.c_str());
camerasElement->InsertEndChild(cameraElement);
}
// 添加设备列表
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* toolParamElement = doc.NewElement("ToolParam");
toolParamElement->SetAttribute("eulerOrder", configResult.algorithmParams.toolParam.eulerOrder);
toolParamElement->SetAttribute("rotX", configResult.algorithmParams.toolParam.rotX);
toolParamElement->SetAttribute("rotY", configResult.algorithmParams.toolParam.rotY);
toolParamElement->SetAttribute("rotZ", configResult.algorithmParams.toolParam.rotZ);
toolParamElement->SetAttribute("offsetX", configResult.algorithmParams.toolParam.offsetX);
toolParamElement->SetAttribute("offsetY", configResult.algorithmParams.toolParam.offsetY);
toolParamElement->SetAttribute("offsetZ", configResult.algorithmParams.toolParam.offsetZ);
algoParamsElement->InsertEndChild(toolParamElement);
XMLElement* modelParamElement = doc.NewElement("WorkpieceModelParam");
modelParamElement->SetAttribute("minimumScore",
configResult.algorithmParams.modelParam.minimumScore);
modelParamElement->SetAttribute("class0WorkpieceType",
configResult.algorithmParams.modelParam.class0WorkpieceType);
modelParamElement->SetAttribute("class1WorkpieceType",
configResult.algorithmParams.modelParam.class1WorkpieceType);
modelParamElement->SetAttribute("class2WorkpieceType",
configResult.algorithmParams.modelParam.class2WorkpieceType);
algoParamsElement->InsertEndChild(modelParamElement);
XMLElement* fullImageCaptureElement = doc.NewElement("FullImageCaptureParam");
fullImageCaptureElement->SetAttribute("exposure",
configResult.algorithmParams.fullImageCaptureParam.exposure);
fullImageCaptureElement->SetAttribute("gain",
configResult.algorithmParams.fullImageCaptureParam.gain);
algoParamsElement->InsertEndChild(fullImageCaptureElement);
XMLElement* binParamElement = doc.NewElement("BinParam");
const VrBinParam& binParam = configResult.algorithmParams.binParam;
binParamElement->SetAttribute("useConfiguredBin", binParam.useConfiguredBin);
binParamElement->SetAttribute("binHeight", binParam.binHeight);
binParamElement->SetAttribute("length", binParam.length);
binParamElement->SetAttribute("width", binParam.width);
binParamElement->SetAttribute("binTopZ", binParam.binTopZ);
auto writeVec3 = [binParamElement](const char* prefix, const double values[3]) {
char attrName[64];
for (int i = 0; i < 3; ++i) {
sprintf(attrName, "%s%d", prefix, i);
binParamElement->SetAttribute(attrName, values[i]);
}
};
writeVec3("center", binParam.center);
writeVec3("bottomNormal", binParam.bottomNormal);
writeVec3("xDir", binParam.xDir);
writeVec3("yDir", binParam.yDir);
for (int vertex = 0; vertex < 4; ++vertex) {
char attrName[64];
for (int axis = 0; axis < 3; ++axis) {
sprintf(attrName, "minRectVertex%d_%d", vertex, axis);
binParamElement->SetAttribute(attrName, binParam.minRectVertex[vertex][axis]);
}
}
algoParamsElement->InsertEndChild(binParamElement);
XMLElement* rotorCoreParamElement = doc.NewElement("RotorCoreParam");
rotorCoreParamElement->SetAttribute("radius", configResult.algorithmParams.rotorCoreParam.radius);
rotorCoreParamElement->SetAttribute("height", configResult.algorithmParams.rotorCoreParam.height);
algoParamsElement->InsertEndChild(rotorCoreParamElement);
// 添加多相机平面校准参数
XMLElement* planeCalibParamsElement = doc.NewElement("PlaneCalibParams");
for (const auto& cameraParam : configResult.algorithmParams.planeCalibParam.cameraCalibParams)
{
XMLElement* cameraCalibParamElement = doc.NewElement("CameraCalibParam");
cameraCalibParamElement->SetAttribute("cameraIndex", cameraParam.cameraIndex);
cameraCalibParamElement->SetAttribute("cameraName", cameraParam.cameraName.c_str());
cameraCalibParamElement->SetAttribute("isCalibrated", cameraParam.isCalibrated);
cameraCalibParamElement->SetAttribute("planeHeight", cameraParam.planeHeight);
// 保存旋转矩阵planeCalib[9] (3x3矩阵)
cameraCalibParamElement->SetAttribute("planeCalib_00", cameraParam.planeCalib[0]);
cameraCalibParamElement->SetAttribute("planeCalib_01", cameraParam.planeCalib[1]);
cameraCalibParamElement->SetAttribute("planeCalib_02", cameraParam.planeCalib[2]);
cameraCalibParamElement->SetAttribute("planeCalib_10", cameraParam.planeCalib[3]);
cameraCalibParamElement->SetAttribute("planeCalib_11", cameraParam.planeCalib[4]);
cameraCalibParamElement->SetAttribute("planeCalib_12", cameraParam.planeCalib[5]);
cameraCalibParamElement->SetAttribute("planeCalib_20", cameraParam.planeCalib[6]);
cameraCalibParamElement->SetAttribute("planeCalib_21", cameraParam.planeCalib[7]);
cameraCalibParamElement->SetAttribute("planeCalib_22", cameraParam.planeCalib[8]);
// 保存逆旋转矩阵invRMatrix[9] (3x3矩阵)
cameraCalibParamElement->SetAttribute("invRMatrix_00", cameraParam.invRMatrix[0]);
cameraCalibParamElement->SetAttribute("invRMatrix_01", cameraParam.invRMatrix[1]);
cameraCalibParamElement->SetAttribute("invRMatrix_02", cameraParam.invRMatrix[2]);
cameraCalibParamElement->SetAttribute("invRMatrix_10", cameraParam.invRMatrix[3]);
cameraCalibParamElement->SetAttribute("invRMatrix_11", cameraParam.invRMatrix[4]);
cameraCalibParamElement->SetAttribute("invRMatrix_12", cameraParam.invRMatrix[5]);
cameraCalibParamElement->SetAttribute("invRMatrix_20", cameraParam.invRMatrix[6]);
cameraCalibParamElement->SetAttribute("invRMatrix_21", cameraParam.invRMatrix[7]);
cameraCalibParamElement->SetAttribute("invRMatrix_22", cameraParam.invRMatrix[8]);
planeCalibParamsElement->InsertEndChild(cameraCalibParamElement);
}
algoParamsElement->InsertEndChild(planeCalibParamsElement);
// 添加调试参数在AlgorithmParams外面
XMLElement* debugParamElement = doc.NewElement("DebugParam");
debugParamElement->SetAttribute("enableDebug", configResult.debugParam.enableDebug);
debugParamElement->SetAttribute("savePointCloud", configResult.debugParam.savePointCloud);
debugParamElement->SetAttribute("saveDebugImage", configResult.debugParam.saveDebugImage);
debugParamElement->SetAttribute("printDetailLog", configResult.debugParam.printDetailLog);
debugParamElement->SetAttribute("debugOutputPath", configResult.debugParam.debugOutputPath.c_str());
root->InsertEndChild(debugParamElement);
// 添加串口配置
XMLElement* serialConfigElement = doc.NewElement("SerialConfig");
serialConfigElement->SetAttribute("portName", configResult.serialConfig.portName.c_str());
serialConfigElement->SetAttribute("baudRate", configResult.serialConfig.baudRate);
serialConfigElement->SetAttribute("dataBits", configResult.serialConfig.dataBits);
serialConfigElement->SetAttribute("stopBits", configResult.serialConfig.stopBits);
serialConfigElement->SetAttribute("parity", configResult.serialConfig.parity);
serialConfigElement->SetAttribute("flowControl", configResult.serialConfig.flowControl);
serialConfigElement->SetAttribute("enabled", configResult.serialConfig.enabled);
root->InsertEndChild(serialConfigElement);
// 添加手眼标定矩阵
XMLElement* handEyeElement = doc.NewElement("HandEyeCalibMatrix");
for (int i = 0; i < 16; i++)
{
char attrName[32];
sprintf(attrName, "m%d", i);
handEyeElement->SetAttribute(attrName, configResult.handEyeCalibMatrix.matrix[i]);
}
// 保存旋转顺序
handEyeElement->SetAttribute("eulerOrder", configResult.handEyeCalibMatrix.eulerOrder);
root->InsertEndChild(handEyeElement);
// 添加 TCP/IP 文本服务端端口和 Modbus 寄存器配置
XMLElement* tcpServerConfigElement = doc.NewElement("TcpServerConfig");
tcpServerConfigElement->SetAttribute("robotServerPort", configResult.plcRobotServerConfig.robotServerPort);
// 保存Modbus寄存器地址配置
tcpServerConfigElement->SetAttribute("addrTrigger", configResult.plcRobotServerConfig.registerConfig.addrTrigger);
tcpServerConfigElement->SetAttribute("addrWorkStatus", configResult.plcRobotServerConfig.registerConfig.addrWorkStatus);
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;
}