SMT 贴片机上位机项目

SMT 贴片机上位机项目

SMT 贴片机上位机项目场景,针对面试问题进行代码层面的分析与整理,聚焦核心代码框架及设计思路:

一、上位机软件架构设计(对应问题 1)

1. 分层架构代码框架
复制代码
// 1. 硬件抽象层(Hardware Abstraction Layer)
// 运动控制卡封装
public interface IMotionController
{
    bool Initialize();
    void MoveTo(int axis, double position, double speed); // 单轴运动
    void SyncMove(List<Tuple<int, double>> axisPositions, double speed); // 多轴同步运动
    double GetCurrentPosition(int axis);
    event Action<string> ErrorOccurred; // 错误事件
}
​
public class GTSMotionController : IMotionController
{
    // 封装固高GTS控制卡DLL调用
    [DllImport("GTS.dll")]
    private static extern int GTS_Init();
    
    public bool Initialize()
    {
        return GTS_Init() == 0; // 调用底层初始化函数
    }
    
    public void MoveTo(int axis, double position, double speed)
    {
        // 转换物理位置为脉冲(基于脉冲当量计算)
        int pulses = (int)(position / _pulseEquivalent);
        GTS_Move(axis, pulses, (int)speed); // 调用运动函数
    }
    // 其他实现...
}
​
// 视觉库封装
public interface IVisionProcessor
{
    (double x, double y, double angle) LocateMark(string imagePath); // 定位Mark点
    void SetCameraParam(int exposure, int gain);
}
​
public class HalconVisionProcessor : IVisionProcessor
{
    // 封装Halcon函数
    public (double x, double y, double angle) LocateMark(string imagePath)
    {
        HOperatorSet.ReadImage(out HObject image, imagePath);
        // 调用Halcon定位算子(阈值分割、模板匹配等)
        HOperatorSet.FindShapeModel(...); 
        return (x, y, angle); // 返回定位结果
    }
}
​
​
// 2. 业务逻辑层(Business Logic Layer)
public class MountingService
{
    private readonly IMotionController _motionController;
    private readonly IVisionProcessor _visionProcessor;
    private readonly IRecipeRepository _recipeRepo;
​
    // 依赖注入(解耦硬件与业务逻辑)
    public MountingService(IMotionController motion, IVisionProcessor vision, IRecipeRepository repo)
    {
        _motionController = motion;
        _visionProcessor = vision;
        _recipeRepo = repo;
    }
​
    // 核心业务:执行贴装流程
    public async Task ExecuteMounting(string recipeId)
    {
        var recipe = await _recipeRepo.GetRecipeAsync(recipeId); // 获取贴装配方
        await CalibrateVision(); // 视觉校准(九点标定)
        
        foreach (var component in recipe.Components)
        {
            // 1. 移动到取料位置
            await _motionController.MoveToAsync(0, component.PickX, component.PickY);
            // 2. 视觉定位元件
            var (x, y, angle) = _visionProcessor.LocateMark(component.ImagePath);
            // 3. 补偿位置后贴装
            await _motionController.MoveToAsync(0, component.PlaceX + x, component.PlaceY + y);
            // 4. 控制真空阀贴装
            await _ioService.SetOutputAsync("Vacuum", false); 
        }
    }
}
​
​
// 3. 表示层(MVVM模式)
public class MountingViewModel : BindableBase // Prism的BindableBase实现INotifyPropertyChanged
{
    private readonly MountingService _mountingService;
    private string _currentStatus;
​
    public string CurrentStatus
    {
        get => _currentStatus;
        set => SetProperty(ref _currentStatus, value);
    }
​
    public DelegateCommand<string> StartMountingCommand { get; }
​
    public MountingViewModel(MountingService service)
    {
        _mountingService = service;
        StartMountingCommand = new DelegateCommand<string>(async (recipeId) => 
        {
            CurrentStatus = "开始贴装...";
            await _mountingService.ExecuteMounting(recipeId); // 调用业务层
            CurrentStatus = "贴装完成";
        });
    }
}
2. 采用 MVVM / 分层架构的好处
  • 解耦性 :硬件抽象层隔离了运动控制卡、视觉库的具体实现,更换硬件时只需修改对应实现类(如从固高卡换成雷塞卡,只需新增LeisaiMotionController实现IMotionController)。

  • 可维护性 :业务逻辑集中在服务类,避免与 UI 代码混杂,例如贴装流程的修改只需调整MountingService,不影响 UI。

  • 可测试性 :通过接口注入,可使用模拟对象(Moq)进行单元测试(如用Mock<IMotionController>模拟运动控制,无需真实硬件)。

  • 多团队协作:UI 团队专注于 XAML 和 ViewModel,控制团队专注于硬件抽象和业务逻辑,并行开发。

二、与硬件的交互方式(对应问题 2)

  1. 运动控制卡交互 :通过DLL 导入(P/Invoke) 调用底层驱动

    • 固高 GTS 控制卡提供 C 语言 DLL,通过[DllImport]声明导入,封装成 C# 接口(如IMotionController),避免直接在业务层调用非托管代码。

    • 关键代码见上文GTSMotionController,核心是脉冲换算 (物理位置→脉冲数)和异步封装 (将同步 DLL 调用转为Task,避免阻塞 UI)。

  2. 视觉库交互 :通过Halcon .NET 封装库 (如halcondotnet.dll

    • 直接引用 Halcon 的 C# 类库,封装IVisionProcessor接口,隐藏复杂的视觉算法细节,业务层只需调用LocateMark等方法。

    • 示例:定位 Mark 点时,先通过相机 SDK 获取图像,再传入视觉处理器进行处理,返回坐标补偿值。

三、上位机与 PLC 的分工与通信(对应问题 3)

1. 分工
  • 上位机:负责高精度运动控制(贴装头定位)、视觉定位、配方管理、生产调度、数据统计。

  • PLC:负责辅助机构控制(传送带启停、顶针升降、安全门检测)、I/O 信号采集(传感器状态)、紧急停止处理。

2. 通信实现(TCP/IP 协议)
复制代码
public class PlcCommunicator
{
    private TcpClient _client;
    private NetworkStream _stream;
​
    public async Task Connect(string ip, int port)
    {
        _client = new TcpClient();
        await _client.ConnectAsync(ip, port);
        _stream = _client.GetStream();
    }
​
    // 发送指令:例如控制传送带启动
    public async Task SendCommand(PlcCommand command)
    {
        byte[] data = PlcProtocol.Encode(command); // 按自定义协议编码(如地址+指令+校验)
        await _stream.WriteAsync(data, 0, data.Length);
    }
​
    // 接收PLC状态:例如顶针到位信号
    public async Task<PlcStatus> ReceiveStatus()
    {
        byte[] buffer = new byte[1024];
        int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
        return PlcProtocol.Decode<PlcStatus>(buffer, bytesRead);
    }
}
​
// 业务层调用
public async Task StartConveyor()
{
    await _plcCommunicator.SendCommand(new PlcCommand { Address = 0x01, Command = "ConveyorStart" });
    // 等待PLC反馈启动成功
    var status = await _plcCommunicator.ReceiveStatus();
    if (!status.ConveyorRunning)
        throw new Exception("传送带启动失败");
}

四、多线程设计(对应问题 4)

采用线程池 + Task 调度,按功能划分线程:

  1. UI 线程:负责界面渲染(WPF 主线程),仅处理 UI 更新,不执行耗时操作。

  2. 运动控制线程

    :通过Task.Run

    在后台线程执行运动指令,确保实时性(避免被 UI 阻塞)。

    复制代码
    // 运动服务中的异步封装
    public async Task MoveToAsync(int axis, double position, double speed)
    {
        // 在线程池线程中执行同步运动函数
        await Task.Run(() => _motionController.MoveTo(axis, position, speed));
    }
  3. 视觉处理线程

    :独立Task

    处理图像识别(CPU 密集型),避免占用运动控制线程。

    复制代码
    public async Task<(double x, double y)> LocateAsync(string imagePath)
    {
        return await Task.Run(() => _visionProcessor.LocateMark(imagePath));
    }
  4. 通信线程 :专用Task循环接收 PLC / 设备数据(await _stream.ReadAsync),通过ConcurrentQueue缓存数据,避免阻塞。

  5. 日志线程:单线程消费日志队列,异步写入数据库 / 文件(避免高频日志 IO 阻塞业务)。

线程安全保障

  • UI 更新:通过Dispatcher(WPF)或BeginInvoke切换到 UI 线程。

  • 共享数据:使用ConcurrentDictionarylockSemaphoreSlim保护临界资源(如当前设备状态)。

五、数据设计与数据库(对应问题 5)

1. 数据库选型:SQL Server(生产数据)+ SQLite(本地配方)
2. 核心表结构
复制代码
-- 配方表(存储贴装参数)
CREATE TABLE Recipes (
    RecipeId INT PRIMARY KEY,
    ProductName NVARCHAR(100),
    CreatedTime DATETIME,
    LastModifiedTime DATETIME
);
​
-- 元件表(每个配方包含多个元件)
CREATE TABLE Components (
    ComponentId INT PRIMARY KEY,
    RecipeId INT FOREIGN KEY REFERENCES Recipes(RecipeId),
    PartNumber NVARCHAR(50), -- 元件型号
    PickX FLOAT, -- 取料X坐标
    PickY FLOAT, -- 取料Y坐标
    PlaceX FLOAT, -- 贴装X坐标
    PlaceY FLOAT, -- 贴装Y坐标
    VisionTemplatePath NVARCHAR(200) -- 视觉模板路径
);
​
-- 生产记录表
CREATE TABLE ProductionLogs (
    LogId INT PRIMARY KEY,
    RecipeId INT,
    StartTime DATETIME,
    EndTime DATETIME,
    TotalCount INT, -- 总贴装数
    GoodCount INT, -- 良品数
    ErrorInfo NVARCHAR(MAX)
);
3. 数据访问层实现(使用 EF Core)
复制代码
public class RecipeRepository : IRecipeRepository
{
    private readonly AppDbContext _dbContext;
​
    public async Task<Recipe> GetRecipeAsync(string recipeId)
    {
        return await _dbContext.Recipes
            .Include(r => r.Components)
            .FirstOrDefaultAsync(r => r.RecipeId == recipeId);
    }
​
    public async Task SaveProductionLogAsync(ProductionLog log)
    {
        _dbContext.ProductionLogs.Add(log);
        await _dbContext.SaveChangesAsync();
    }
}

六、棘手问题及解决方案(对应问题 6)

问题:高速贴装时视觉定位延迟导致贴装偏移
  • 现象:当贴装速度超过 20,000 CPH 时,视觉定位结果滞后于运动控制,导致元件贴装位置偏移。

  • 分析:视觉处理(模板匹配)耗时约 50ms,而运动控制周期仅 30ms,两者不同步。

  • 解决方案

    1. 预缓存定位结果

      :在贴装前提前对下一元件进行视觉定位,缓存结果(使用ConcurrentQueue)

      复制代码
      // 预加载线程
      private async Task PreloadVisionResults(Recipe recipe)
      {
          foreach (var comp in recipe.Components)
          {
              var result = await _visionProcessor.LocateMark(comp.ImagePath);
              _visionResultQueue.Enqueue(result); // 缓存到队列
          }
      }
    2. 运动与视觉并行处理

      :使用Task.WhenAll

      同时执行当前元件贴装和下一元件视觉定位。

      复制代码
      // 并行处理
      var currentMountTask = _motionController.MoveToAsync(placeX, placeY);
      var nextVisionTask = _visionProcessor.LocateMark(nextComp.ImagePath);
      await Task.WhenAll(currentMountTask, nextVisionTask); // 时完成
    3. 优化视觉算法 :通过 Halcon 的CreateShapeModel创建高效模板,减少匹配区域(ROI),将处理时间压缩至 20ms 以内。

  • 结果:贴装速度提升至 25,000 CPH 时仍保持定位精度(±0.02mm)。

以上代码框架和设计思路覆盖了 SMT 贴片机上位机的核心技术点,可直接用于面试中对项目细节的阐述,突出架构设计、多线程、硬件交互等关键能力

相关推荐
我不是懒洋洋2 小时前
【经典题目】链表OJ(相交链表、环形链表、环形链表II、随机链表的复制)
c语言·开发语言·数据结构·链表·ecmascript·visual studio
ん贤2 小时前
口述Map
开发语言·面试·golang
YuanDaima20482 小时前
Python 数据结构与语法速查笔记
开发语言·数据结构·人工智能·python·算法
asdzx672 小时前
C#:从 URL 下载 PDF 文档到本地
开发语言·pdf·c#
阿凤212 小时前
uniapp如何修改下载文件位置
开发语言·前端·javascript
m0_716765232 小时前
数据结构--循环链表、双向链表的插入、删除、查找详解
开发语言·数据结构·c++·学习·链表·青少年编程·visual studio
聆风吟º2 小时前
【C标准库】深入理解C语言strstr函数:子字符串查找的实用指南
c语言·开发语言·库函数·strstr
XY_墨莲伊2 小时前
【编译原理】实验一:基于正则文法的词法分析器设计与实现
开发语言·数据结构·算法
Tirzano2 小时前
springsession全能序列化方案
java·开发语言