去年在自动化产线升级项目中,我遇到了一个典型需求:需要通过上位机同时控制PLC设备并集成视觉检测功能。经过技术选型,最终采用C#开发上位机程序,通过Modbus TCP协议与台达PLC通信,并整合Halcon视觉库实现产品缺陷检测。这套方案在实际产线中稳定运行了8个月,处理了超过200万件产品检测。
这个方案最大的优势在于将控制与检测功能集成在单一上位机中,避免了传统方案中PLC与视觉控制器分开导致的协同问题。下面我将从通信实现、视觉集成和系统架构三个维度,详细拆解这个项目的技术细节。
选择VS2019作为开发环境主要基于以下考量:
注意:必须安装VS2019的"使用C++的桌面开发"工作负载,因为Halcon的C#封装依赖C++运行时库。
通过NuGet安装以下关键包:
安装时需要特别注意版本匹配:
bash复制Install-Package NModbus4 -Version 1.13.1
Install-Package HalconDotNet -Version 20.11.0
台达PLC的Modbus TCP实现有以下特点:
建议采用分层架构设计通信模块:
csharp复制public class PlcService : IDisposable
{
private readonly ModbusFactory _modbusFactory = new ModbusFactory();
private IModbusMaster _master;
private TcpClient _tcpClient;
public bool IsConnected => _tcpClient?.Connected ?? false;
public void Connect(string ip, int port = 502)
{
_tcpClient = new TcpClient(ip, port);
_master = _modbusFactory.CreateMaster(_tcpClient);
// 设置超时避免阻塞
_master.Transport.ReadTimeout = 1000;
_master.Transport.WriteTimeout = 1000;
}
public ushort[] ReadRegisters(byte slaveId, ushort startAddress, ushort count)
{
return _master.ReadHoldingRegisters(slaveId, startAddress, count);
}
public void WriteRegisters(byte slaveId, ushort startAddress, ushort[] data)
{
_master.WriteMultipleRegisters(slaveId, startAddress, data);
}
public void Dispose()
{
_master?.Dispose();
_tcpClient?.Close();
}
}
csharp复制public bool CheckConnection()
{
try
{
return _master.ReadHoldingRegisters(0, 0, 1) != null;
}
catch
{
return false;
}
}
csharp复制public void SafeWrite(Action operation, int maxRetries = 3)
{
int retryCount = 0;
while (retryCount < maxRetries)
{
try
{
operation();
return;
}
catch (SocketException ex) when (retryCount < maxRetries - 1)
{
Thread.Sleep(100);
retryCount++;
}
}
}
csharp复制HOperatorSet.SetSystem("use_window_thread", "true");
典型检测流程实现示例:
csharp复制public class VisionProcessor
{
private HWindow _window;
private HImage _currentImage;
public VisionResult ProcessImage(string imagePath)
{
try
{
_currentImage?.Dispose();
_currentImage = new HImage(imagePath);
// 图像预处理
HImage grayImage = _currentImage.Rgb1ToGray();
HRegion thresholdRegion = grayImage.Threshold(0, 120);
// 特征提取
HXLDCont contours = thresholdRegion.EdgesSubPix("canny", 1, 20, 40);
// 结果分析
return AnalyzeContours(contours);
}
finally
{
grayImage?.Dispose();
thresholdRegion?.Dispose();
contours?.Dispose();
}
}
private VisionResult AnalyzeContours(HXLDCont contours)
{
// 实现具体检测逻辑
}
}
csharp复制public async Task<VisionResult> ProcessImageAsync(string path)
{
return await Task.Run(() => ProcessImage(path));
}
csharp复制HOperatorSet.SetSystem("use_gpu", "true");
HOperatorSet.QueryAvailableComputeDevices(out HTuple deviceHandles);
HOperatorSet.ActivateComputeDevice(deviceHandles[0]);
建议采用状态机模式管理业务流程:
csharp复制public enum SystemState
{
Idle,
WaitingTrigger,
ProcessingImage,
WritingResult,
Error
}
public class SystemController
{
private SystemState _currentState;
private readonly PlcService _plc;
private readonly VisionProcessor _vision;
public async Task RunCycleAsync()
{
while (true)
{
switch (_currentState)
{
case SystemState.Idle:
await CheckTrigger();
break;
case SystemState.WaitingTrigger:
await ProcessTrigger();
break;
// 其他状态处理...
}
await Task.Delay(50);
}
}
private async Task CheckTrigger()
{
var inputs = _plc.ReadRegisters(0, 100, 1);
if (inputs[0] == 1)
{
_currentState = SystemState.WaitingTrigger;
}
}
}
建议建立三级异常处理机制:
实现示例:
csharp复制public class ErrorHandler
{
public void Handle(Exception ex)
{
if (ex is SocketException)
{
// 网络通信异常处理
_plc.Reconnect();
}
else if (ex is HOperatorException)
{
// 视觉处理异常
_vision.Reset();
}
else
{
// 系统级异常
EmergencyStop();
}
}
}
csharp复制HImage ApplyLightCompensation(HImage image)
{
HImage median = image.MedianImage("circle", 3, "mirrored");
HImage diff = image.SubImage(median, 1, 0);
return diff.ScaleImage(1.2, 0);
}
这套系统经过多个项目的验证,在汽车零部件检测、电子元件装配等场景都取得了良好效果。特别是在一个刹车片检测项目中,将误检率从传统方案的3.2%降低到了0.8%,同时检测速度提升了40%。