项目概览

SmartEarInspect 是一套面向耳机生产线的 Windows 智能检测工作站软件。系统把治具运动、数字 IO、安全信号、CCD/AOI 字符与外观检测、颜色检测、MES 数据、质量记录和操作权限编排在同一个可追踪流程中,使操作员面对的是稳定的工位状态和检测结果,而不是分散的控制器、串口、网络与相机协议。

该系统已经在真实产线中正式使用。运动控制、IO 与安全联锁、CCD/AOI、颜色检测、MES 国别适配、权限、指纹登录、审计、检测追溯和备份能力均经过现场使用。本文只作定性总结,不公开客户、具体产品型号、产线拓扑、设备品牌、工艺参数、接口字段、地址端口、节拍、产量、良率或稳定性指标。

本文以稳定源码提交 2fd7f08 为整理基线。该基线可独立完成 Release 构建,并通过全部 500 项自动化测试。正在进行但尚未进入稳定基线的本地重构不作为本文成果。

项目背景与目标

耳机字符、颜色和外观检测并不是“拍一张照片再显示 PASS/NG”这么简单。完整工位需要同时处理:

  • 操作员身份与权限;
  • 设备连接、自检、回零与安全状态;
  • SN 输入、MES 查询和动态预期值;
  • 不同国别或型号对应的检测点组合;
  • 治具在多个拍摄和传感位置之间运动;
  • CCD/AOI 请求、结果与图像的异步到达;
  • RS485 或数字 IO 类型的颜色传感器;
  • 暂停、停止、异常、断线和恢复;
  • 检测记录、图片索引、审计与备份。

如果这些逻辑全部堆在 WPF 窗口事件中,硬件状态、界面状态和业务状态会快速耦合。项目因此把目标确定为:用状态机表达生产流程,用接口隔离硬件差异,用配置表达可变工艺,用本地数据保存质量证据,并让没有真实设备的开发环境仍可推进功能开发。

设计原则与安全边界

系统实现遵循以下原则:

  1. 流程与设备分离:工作流只依赖业务语义接口,不直接调用厂商 API;
  2. 界面与业务分离:ViewModel 负责命令和可观察状态,View 只负责绑定与交互;
  3. 真实与 Mock 同契约:开发环境替换设备实现,不复制另一套业务流程;
  4. 配置驱动工艺:检测点、运动参数、国别规则与 IO 映射由配置装配;
  5. 失败必须收敛:超时、取消和异常都要回到可解释状态并执行清理;
  6. 结果必须留痕:检测记录、明细和关键操作进入本地持久化与审计链路;
  7. 最小权限操作:管理、调试、配置和生产操作按角色与功能权限控制。

上位机软件不替代安全继电器、硬接线急停、驱动器保护或设备风险评估。软件中的双手启动、安全门、光栅和停止逻辑是控制层防护,必须与现场电气安全回路共同工作。

技术栈与运行约束

领域 技术 主要职责
桌面运行时 .NET 8 / C# / WPF Windows x64 工位应用、异步流程和数据绑定
表现层 MVVM / CommunityToolkit.Mvvm 可观察状态、命令与 ViewModel 生成
依赖装配 Microsoft.Extensions.DependencyInjection 配置、服务、ViewModel 与设备实现生命周期
数据存储 EF Core / SQLite 用户、权限、审计、检测记录和结果明细
日志 NLog / Microsoft.Extensions.Logging 启动、设备、流程、异常与运维日志
外部通信 TCP / HTTP / RS485 / 数字 IO AOI、MES、颜色传感器和现场信号
图像通道 MemoryMappedFile / 命名事件 跨进程图像帧传输与新帧通知
运动控制 独立 MotionControl 库 控制器、轴、回零、点位运动与 IO
自动化测试 xUnit / Moq 业务、数据、通讯并发和基础设施验证

主程序目标框架为 net8.0-windows8.0,Release 输出面向 win-x64。真实运行还依赖设备驱动、原生运行库以及与现场一致的配置文件,因此“源码可构建”和“工位可投产”是两个不同的验收层级。

分层架构

系统以 App.xaml.cs 为装配入口,把配置、基础设施、业务服务、设备适配和 MVVM 表现层串成单向依赖链:

Operator / MainWindow


InspectionViewModel
        │  commands, progress, images, result presentation

InspectionWorkflow
        │  state machine, safety, motion, lifecycle

InspectionService
        │  point-level inspection and result aggregation
        ├───────────────┬────────────────┬─────────────────┐
        ▼               ▼                ▼                 ▼
Motion + IO        CCD / AOI       Color Sensor      MES / Rules
        │               │                │                 │
        └───────────────┴────────────────┴─────────────────┘


                    InspectionDataService


                       EF Core / SQLite

核心调用关系可以概括为:

InspectionViewModel
    └── InspectionWorkflow
            ├── InspectionService
            ├── IMotionControllerProvider
            ├── IInspectionIoService
            ├── IInspectionExecutionPlanBuilder
            └── IInspectionDataService

InspectionViewModel 不直接读写控制卡或串口;InspectionWorkflow 不关心按钮、表格和图片控件;设备服务也不决定一个生产周期应该经过哪些状态。这种边界使 UI、工艺和设备协议能够分别演进。

启动与依赖装配

应用启动过程本身是一条受控链路:

  1. 注册 UI、非 UI 线程和未观察 Task 的全局异常处理;
  2. 加载主配置与专项配置,初始化日志目录;
  3. 建立依赖注入容器,注册配置、服务、ViewModel 和窗口;
  4. 初始化多语言服务;
  5. 执行 EF Core 数据库迁移、权限同步和基础数据初始化;
  6. 初始化运动控制提供者;
  7. 建立权限到 WPF 可见性和可用性的绑定;
  8. 解析并显示主窗口。

有运行状态的组件,例如运动控制器、检测工作流、IO 服务和当前用户上下文,使用与应用生命周期一致的单例;无状态数据访问服务通过 IDbContextFactory 按操作创建上下文,避免在长期运行的 UI 进程中共享同一个 DbContext

检测状态机

一轮检测不是一组松散按钮事件,而是由 InspectionWorkflow 驱动的状态机:

登录与权限确认

设备自检与运动轴回零

输入产品标识并查询 MES

解析国别规则与动态预期值

等待双手启动和安全条件

治具移动到检测位置

按执行计划逐点运动与检测

综合 PASS / NG 判定

保存记录、明细和审计信息

治具回原位并进入下一周期

状态机明确表达空闲、等待启动、治具运动、CCD 检测、颜色检测、判定、保存、回原位、暂停、完成和错误等状态。界面通过事件接收状态、进度、日志、单点结果和周期完成通知,不轮询内部业务对象。

调用侧只需要准备运行上下文并交给工作流,硬件步骤留在工作流与设备服务内部。以下代码为删除现场细节后的简化示意:

var selfCheck = await workflow.PreCheckDevicesAsync(cancellationToken);
if (!selfCheck.AllPassed)
{
    return;
}

var record = await workflow.ExecuteAsync(runtimeContext, cancellationToken);
ShowResult(record);

手动模式执行一个周期后停止;自动模式在每轮结束后重新进入启动确认,并根据配置决定是否为下一件产品重新获取运行上下文。停止策略同时支持立即取消和完成当前周期后停止,暂停则通过显式检查点阻断后续步骤。

MES、动态预期值与国别适配

现场产品的检测内容并不总是固定。系统在设备自检完成后获取产品标识,通过可配置的 HTTP 适配器查询 MES,再把返回内容转换为统一运行上下文:

Operator input
    → MES provider
    → response parser
    → expected-value mapper
    → country profile resolver
    → inspection execution plan

运行上下文保存本周期的产品标识、动态预期值、国别信息以及允许执行的识别项。执行计划构建器先按启用状态和顺序整理检测点,再根据国别规则过滤不适用的识别项;预期值解析器优先使用本周期动态值,没有覆盖时才回退到配置值。

MES 适配器具备请求取消、HTTP 状态检查和响应编码处理。解析器会拒绝空响应、格式异常或缺少关键业务信息的返回,避免把不完整数据悄悄带入检测。本文不展示真实请求模板、响应字段、国别代码和预期内容;这些都属于现场配置和业务接口边界。

运动控制与语义 IO

SmartEarInspect 复用独立的 MotionControl 库接入工业运动控制器。上层通过 IMotionControllerProvider 管理驱动选择、初始化、连接、回零、轴配置与控制器生命周期,不在检测代码中出现厂商句柄和原始错误码。

检测点同时描述运动位置和检测类型。工作流移动到点位、等待到位,再调用对应检测服务;直线轴与旋转轴的具体单位、回零和运动细节由运动控制层负责。

物理 IO 被进一步封装为业务语义,例如:

  • 左右启动按钮与按钮灯;
  • 安全门、光栅和物料检测;
  • 红黄绿灯与蜂鸣器;
  • 颜色传感器开关量输出;
  • 定位气缸、真空和破真空输出。

IO 索引、类型和反向逻辑来自配置,业务层只调用 IsSystemSafe()WaitForDualHandStartAsync()SetTriColorLight() 这类语义方法。底层监控器将数字输入变化转换为事件,减少 UI 与流程代码对物理点位的硬编码。

CCD/AOI 通讯与图像通道

视觉系统使用两条职责不同的通路:

通路 内容 设计重点
TCP 触发请求、PASS/NG、识别文本和扩展结果 超时、取消、响应完整性、断线与重连
共享内存 原始图像帧与帧元数据 双缓冲、写入完成标记、命名事件通知

TCP 结果通道

CCD 客户端建立长连接后,以一次完整的“发送请求 + 接收 JSON”作为不可分割的 IO 区间。单一异步锁串行化并发触发,防止不同检测点的响应交叉消费。响应读取不依赖单次网络包或固定换行,而是累积字符并在 JSON 完整后解析;超时、主动取消、空响应、非法 JSON 和连接丢失被转换为明确的检测错误。

当前实现使用操作系统 TCP KeepAlive 与 Socket 状态探测,不向不支持心跳指令的外部 AOI 注入应用层消息。检测时发现断线会进入有限次数、带间隔的重连流程,避免无限快速重试拖垮现场程序。

共享内存图像通道

图像没有附在 TCP 结果中反复编码,而是通过 MemoryMappedFile 传递。共享区包含全局头、帧槽元数据和图像数据,Writer 写入非活动槽后再切换活动索引,并通过命名事件通知 Reader。Reader 校验魔数、版本、尺寸、数据长度和写入完成状态后才发布新帧。

双缓冲减少了读写同一帧造成撕裂的概率,也使结果消息和大体积图像采用各自合适的传输机制。这里不把该方案描述为绝对“零拷贝”:托管数组、WPF 图像转换和显示过程中仍可能产生内存复制。

颜色检测

系统支持两类颜色检测路径:

  • RS485 颜色传感器:读取颜色数据,根据配置选择色差算法并与目标范围比较;
  • 数字 IO 颜色传感器:读取设备已完成判定后的多路开关量组合。

检测类型由点位配置决定,工作流不需要知道串口帧或 DI 地址。颜色结果与 CCD/AOI 结果使用统一的检测项模型进入综合判定和持久化,同时在界面上显示颜色、数值、名称和当前判定状态。

安全、取消与失败清理

工业工作流最重要的不是正常路径,而是异常时能否收敛。项目将以下策略放入工作流和设备层:

  • 启动前检查运动控制器、轴、IO、视觉与颜色设备;
  • 自动连接和回零失败时保留设备级失败原因;
  • 双手启动限制两个输入的最大时间差;
  • 运行中持续检查安全门与光栅,必要时暂停工作流并停止运动;
  • 所有长耗时操作接收 CancellationToken
  • 网络、串口和运动等待都有超时边界;
  • 暂停点只阻断后续动作,不在任意位置继续发送命令;
  • 立即停止与完成当前周期后停止具有不同语义;
  • 异常路径停止持续 JOG、恢复指示灯并尝试让治具返回可控状态;
  • 应用退出时释放服务容器、设备资源与日志系统。

软件对异常的处理目标是“停止继续扩大影响并保留诊断信息”,而不是掩盖故障后强行继续生产。无法确认安全条件时,流程保持失败或暂停状态,交由现场人员检查。

配置、方案与工艺扩展

配置由主应用设置和专项 JSON 共同组成:

Application settings
├── paths, database, logging and language
├── MES and device connection policies
└── environment selection

Inspection configuration
├── workflow mode and stop policy
├── inspection points and ordering
├── country profiles and expected values
├── IO semantic mappings
└── shared-memory image contract

Motion configuration
├── driver selection
├── axes and mechanical parameters
└── controller initialization options

检测方案通过注册表和独立方案文件管理,使产品切换主要发生在配置层。设置界面负责编辑、校验和保存,运行时服务读取强类型配置。复杂工艺变化仍需要版本评审和现场验证,不能因为配置可编辑就跳过安全检查。

数据、权限与可追溯性

系统使用 EF Core 与 SQLite 保存本地生产和管理数据,启动时自动执行迁移并同步权限定义。主要数据域包括:

  • 检测记录、单点结果、图片索引和周期信息;
  • 用户、角色、模块权限与功能权限;
  • 用户操作审计日志;
  • 指纹身份与用户之间的关联信息。

权限不只在业务方法末尾检查,还通过 WPF 绑定控制模块可见性和功能可用性。生产操作、配置、用户管理、调试、记录查询和备份入口可以分配给不同角色。指纹设备用于现场快速登录,密码认证保留为另一条受控入口。

审计服务记录关键操作的操作者、动作类型、目标和时间。备份服务支持完整与增量备份以及恢复流程,覆盖数据库和被纳入策略的业务文件。多语言服务统一界面文本与日志文化,使现场操作和故障定位使用一致的语言上下文。

这些管理能力已经进入现场使用,但本文不公开用户结构、权限清单、指纹模板、数据库文件、备份位置或默认账户信息。

Mock 与无硬件开发

应用根据运行环境为相同接口注入真实实现或 Mock:

能力 Development Production
运动控制 内存模拟控制器与轴 真实工业控制器
CCD/AOI 可配置的模拟结果与图像 TCP 视觉服务与共享内存
颜色检测 模拟颜色与判定 RS485 或数字 IO 传感器
MES 模拟业务响应 现场 HTTP 服务
工位 IO 模拟输入输出状态 控制器数字 IO

Mock 使界面、状态机、配置、记录和异常分支能够在没有设备时开发,也便于构造超时、NG、断线和安全信号变化。它不能证明真实相机曝光、机械精度、现场电气时序或驱动稳定性,最终仍需要实机与硬件在环验证。

自动化测试策略

测试项目使用 xUnit、Moq 和临时 SQLite/文件目录验证关键行为,稳定基线共有 500 项测试:

  • 工作流自检、状态变化、暂停、停止、取消和异常清理;
  • 单点检测、颜色判定、预期值覆盖和综合结果;
  • MES 解析、国别规则和执行计划过滤;
  • 检测记录写入、查询、统计和并发数据访问;
  • TCP 本地回环服务器下的串行、并发、慢响应和断线场景;
  • 共享内存 Writer/Reader、帧元数据与并发读写;
  • IO 语义映射、反向逻辑、双手启动和安全信号;
  • 用户、登录、权限、审计、设置与备份恢复。

TCP 并发测试会启动本地回环服务,验证多个触发请求在单一 IO 锁下不会串包;共享内存测试验证帧槽切换和数据完整性;数据集成测试使用隔离数据库验证真实 EF Core 行为,而不是只验证 Mock 调用次数。

Mock 测试、集成测试和实机测试解决的是不同风险,三者不能互相替代。

构建、安装与现场交付

稳定基线的验证结果如下:

验证项 结果
源码基线 2fd7f08
Release 构建 通过,0 error
自动化测试 500 passed、0 failed、0 skipped
分析器 1 条 xUnit 阻塞式 Task 使用警告
目标平台 Windows x64 / .NET 8

解决方案包含 WPF 主程序、xUnit 测试项目和 Windows 安装工程。现场交付除了应用二进制,还需要匹配的设备驱动、原生依赖、数据库迁移、工艺方案和站点配置。公开仓库或博客内容不携带这些现场资产。

一次可控的交付流程应包括:

  1. 从锁定源码与依赖执行 Release 构建和自动化测试;
  2. 生成带版本号的 Windows x64 安装产物;
  3. 在隔离工位验证数据库升级和配置兼容性;
  4. 完成设备自检、回零、安全 IO、视觉、颜色和 MES 联调;
  5. 使用标准样件验证 PASS、NG、超时和断线分支;
  6. 备份当前程序、数据库和配置后再切换版本;
  7. 保留上一版本安装包和恢复说明。

真实产线使用结果

项目已经将原本分散的运动、视觉、传感器和管理功能整合为一套产线工作站,并在正式生产中使用。可以确认的工程结果包括:

  • 操作员可以从统一界面完成登录、设备确认、启动、检测和结果查看;
  • MES 数据可以在周期开始前驱动预期值和国别检测计划;
  • 运动、IO、安全、CCD/AOI 与颜色检测按同一状态机协同;
  • 检测结果、图片索引、用户操作和配置管理形成可查询记录;
  • 指纹、角色权限、审计和备份覆盖现场管理需求;
  • Mock 与自动化测试支持无硬件开发,实机验收负责验证现场时序和设备行为。

这里没有公布节拍改善比例、产量、良率、故障率或长期在线时间,因为当前没有适合公开且可复核的数据集。实际投产不等同于对外发布性能基准。

已知边界

边界 当前影响 改进方向
一项测试使用阻塞式 Task 操作 构建产生 xUnit 分析警告 改为完整异步测试并把分析警告纳入门禁
MotionControl 使用相邻源码项目引用 独立拉取后不能直接构建完整解决方案 发布版本化内部包并锁定兼容范围
Windows x64 与原生驱动依赖 无法跨平台运行,部署依赖现场环境 建立驱动、运行库和安装包兼容矩阵
设备协议文档存在演进成本 文档可能仍描述旧的应用层心跳 以现行 TCP KeepAlive 行为更新并做协议契约测试
自动化测试不能覆盖机械与电气 模拟通过不代表设备一定安全可靠 增加标准样件和硬件在环回归清单
依赖和安装产物尚未完全统一版本化 升级与回滚需要更多人工核对 建立 CI、版本号、安装包校验和发布记录

此外,现场配置和数据库包含业务数据,必须独立于源码管理。日志需要限制敏感内容并配置保留周期,备份必须验证可恢复性,而不是只确认压缩包已经生成。

后续路线

  1. 消除剩余测试分析警告,将警告策略纳入持续集成;
  2. 把 MotionControl 从相邻源码引用升级为可追踪的版本化依赖;
  3. 为 TCP、共享内存和 MES 适配器建立更明确的协议契约版本;
  4. 建立标准样件、断线、安全信号和设备恢复的硬件在环回归;
  5. 自动执行还原、Release 构建、500 项测试和安装包生成;
  6. 为现场升级增加版本目录、配置迁移、健康检查和可操作回滚;
  7. 建立日志、数据库增长、备份结果和设备离线的基础监控。

项目复盘

SmartEarInspect 最重要的工程价值,不是把更多功能放进一个 WPF 窗口,而是为多设备协同建立了清晰边界:ViewModel 表达交互,状态机表达生产流程,设备接口表达现场能力,运行上下文承载每件产品的动态规则,数据层保存可追溯结果。

项目也说明了工业软件质量不能只用“能构建”或“有很多测试”衡量。500 项测试可以显著降低业务和并发回归风险,但真正的交付仍要面对机械、电气、原生驱动、网络、操作习惯和版本回滚。把这些限制写进架构和发布流程,与实现正常检测路径同样重要。