1. 项目缘起:当传统分拣遇上现代视觉与状态机
在工业自动化领域,物料分拣是一个经典且高频的场景。过去,我们可能依赖光电传感器、机械挡板配合PLC(可编程逻辑控制器)的顺序控制来实现。这种方案稳定,但“笨拙”——它无法识别物料的颜色、形状、尺寸差异,更别提表面缺陷了。一旦产品种类增多或分拣标准变得复杂,硬件的改造成本和程序的调试难度就会呈指数级上升。
我最近接手的一个旧产线升级项目,就完美诠释了这种痛点。客户需要将一条传送带上的混合电子元件(电阻、电容、不同封装的IC)按类型和极性自动分拣到六个不同的料盒中。传统的传感器方案完全无能为力。这正是引入机器视觉(Vision)和有限状态机(Finite State Machine, FSM)的绝佳时机。这个项目的核心,就是构建一个“视觉引导、状态机驱动”的工业分拣自动化系统。它不依赖于某款特定的高端工控机或大型PLC,而是基于更灵活、成本更优的微控制器(Microcontroller)平台,融合了视觉处理与精准的逻辑控制。
简单来说,这套系统的运作逻辑是:“眼睛”看,“大脑”判,“手”来动。视觉系统充当“眼睛”,实时捕捉传送带上的物料图像;运行在微控制器上的FSM程序作为“大脑”,根据视觉的识别结果,判断当前物料属于哪一类,并决定分拣机构(如气动推杆、伺服滑台)该如何动作;最后,由微控制器控制的执行机构作为“手”,完成精准抓取或推送。整个过程,Modbus协议常作为“眼睛”与“大脑”之间,或“大脑”与上层监控系统之间可靠的通信桥梁。
2. 系统核心架构:视觉、控制器与执行机构的协同
一个完整的Vision and FSM-Driven Sorting System,其硬件与软件架构需要精心设计。下图清晰地展示了信息流与控制流的闭环:
flowchart TD A[图像采集触发信号] --> B[工业相机<br>Vision Sensor] B -- 原始图像数据 --> C[视觉处理单元<br>Vision Master/OpenCV] C -- 识别结果<br>(类型/坐标/角度) --> D[主控制器<br>MCU with FSM Core] D -- 位置指令 --> E[运动执行机构<br>伺服/步进电机] D -- 动作指令 --> F[分拣执行机构<br>气动/电动末端] G[人机界面 HMI] -- 任务下发/状态监控 --> D D -- 实时状态/结果反馈 --> G H[物料传感器] -- 到位信号 --> D E & F -- 动作完成信号 --> D D -- 逻辑判断与状态迁移 --> D我们来拆解图中的关键组件及其选型考量:
2.1 视觉感知层:不止于“看见”
视觉部分的核心任务是稳定、快速地提供结构化的识别结果。这不仅仅是装一个摄像头那么简单。
- 工业相机与镜头:不同于消费级USB摄像头,工业相机需要应对振动、光线变化、高速运动。我们通常选择全局快门的CMOS相机,以避免拍摄运动物体时的“果冻效应”。镜头则根据工作距离(WD)和视野(FOV)来计算焦距。例如,传送带宽度300mm,我们需要覆盖350mm的视野以确保边缘物料也能被捕捉,工作距离500mm,那么焦距f ≈ (传感器尺寸 * 工作距离) / 视野。若使用1/1.8英寸传感器(宽约7.2mm),则f ≈ (7.2 * 500) / 350 ≈ 10.3mm,我们会选择一款12mm的定焦镜头。
- 光源与打光:这是视觉项目的成败关键。不合适的打光会让顶级算法也无能为力。对于电子元件分拣,常用的是同轴光源或穹顶光源,以消除表面反光、凸显轮廓。通过反复试验,我们最终采用了红色LED环形光,以高对比度突出元件的金属引脚与塑料本体。
- 视觉处理单元:这里是算法的战场。你有几个选择:
- 工控机+OpenCV:灵活性最高,适合复杂算法(如使用Vision Transformer等深度学习模型进行精细分类)。但成本高,实时性依赖优化。
- 嵌入式视觉模块:如搭载ARM Cortex-A系列的处理模块,集成Linux和优化库,平衡性能与体积。
- 智能相机:一体化设备,内置处理芯片和简单图形化编程工具(如类似Vision Master的拖拉拽方式),开发快,但算法定制能力弱。 在我们的微控制器方案中,为了降低整体复杂度和成本,选择了中档的智能相机,它通过以太网输出JSON格式的识别结果(如
{“type”: “cap_0805”, “x”: 125.3, “y”: 45.1, “angle”: 0.5}),极大简化了主控端的解析逻辑。
2.2 控制决策层:FSM是逻辑的骨架
主控制器我们选用了一款高性能的STM32系列微控制器。它的任务不是进行图像处理,而是高效、可靠地调度整个系统。有限状态机(FSM)是实现这一目标的完美范式。
FSM将系统的行为建模为有限数量的状态、事件和转换。在我们的分拣系统中,状态可以是:
IDLE:空闲,等待物料到来。WAIT_FOR_VISION:物料已触发传感器,等待视觉处理结果。CLASSIFYING:根据视觉结果,内部判断物料类型。MOVE_TO_TARGET:控制伺服滑台运动到对应料盒上方。EXECUTE_SORTING:触发气动推杆,推出物料。ERROR:发生异常(如视觉超时、执行机构卡住)。
事件则是触发状态改变的条件,如物料传感器触发、视觉结果返回、伺服到位信号、超时定时器溢出。
在MCU上,我们通常用switch-case语句或状态表来实现FSM。一个健壮的FSM设计必须包含超时处理(例如,等待视觉结果超过500ms则跳转到ERROR状态)和错误恢复机制。
2.3 通信桥梁:为什么是Modbus?
智能相机、伺服驱动器、触摸屏HMI,这些设备往往来自不同厂商。让它们“说同一种语言”至关重要。Modbus协议,特别是基于TCP/IP的Modbus TCP,因其简单、开放、广泛支持,成为工业领域事实上的通用轻量级通信协议。
在我们的系统中:
- 智能相机作为Modbus TCP服务器,将识别结果(类型码、坐标值)写入其保持寄存器。
- STM32主控制器作为客户端,定期(如每10ms)读取这些寄存器,获取最新结果。
- 同时,STM32也将系统状态(当前状态字、计数、错误码)写入自己的寄存器,供HMI读取显示。
这种解耦使得更换视觉品牌或HMI时,只需调整Modbus地址映射,而无需重写核心控制逻辑。
2.4 执行机构层:精准的末端操作
根据物料特性(重量、尺寸、易损性)选择执行机构。对于轻型电子元件,我们采用:
- 伺服电动滑台:负责将吸嘴或夹爪精确定位到目标料盒上方。通过Modbus RTU或脉冲控制,定位精度可达±0.02mm。
- 真空吸嘴或柔性夹爪:作为末端执行器,完成拾取。由STM32的GPIO口通过继电器控制电磁阀的通断。
3. 软件实现:从状态机设计到代码落地
有了硬件架构,软件就是赋予系统灵魂的部分。核心在于FSM的实现与视觉数据的集成。
3.1 状态机的C语言实现
我们摒弃复杂的第三方框架,用最清晰易懂的方式实现FSM。首先定义所有状态和事件枚举。
// 系统状态定义 typedef enum { SYS_IDLE, SYS_WAIT_VISION, SYS_CLASSIFYING, SYS_MOVING, SYS_SORTING, SYS_ERROR } SystemState_t; // 系统事件定义 typedef enum { EVT_NONE, EVT_SENSOR_TRIGGERED, // 物料传感器触发 EVT_VISION_DATA_READY, // 视觉数据就绪 EVT_MOVE_COMPLETE, // 移动完成 EVT_SORT_COMPLETE, // 分拣完成 EVT_TIMEOUT, // 超时 EVT_RESET // 复位 } SystemEvent_t; // 系统状态机结构体 typedef struct { SystemState_t currentState; uint32_t stateEntryTime; // 进入当前状态的时间戳 VisionResult_t visionData; // 视觉结果缓存 uint8_t targetBin; // 目标料箱编号 } SystemFSM_t;状态机的主循环通常放在一个高优先级的定时器中断或主循环中,它不断检查当前状态和发生的事件,执行相应的动作并迁移到下一个状态。
void SystemFSM_Run(SystemFSM_t *fsm, SystemEvent_t event) { switch (fsm->currentState) { case SYS_IDLE: if (event == EVT_SENSOR_TRIGGERED) { // 动作:触发相机拍照,启动超时计时器 TriggerCameraCapture(); StartTimer(500); // 500ms超时 // 状态迁移 fsm->currentState = SYS_WAIT_VISION; fsm->stateEntryTime = GetSystemTick(); } break; case SYS_WAIT_VISION: if (event == EVT_VISION_DATA_READY) { // 动作:读取并解析Modbus寄存器中的视觉数据 if (ReadVisionData(&fsm->visionData)) { fsm->currentState = SYS_CLASSIFYING; } StopTimer(); } else if (event == EVT_TIMEOUT) { // 动作:记录视觉超时错误 LogError(VISION_TIMEOUT); fsm->currentState = SYS_ERROR; } break; case SYS_CLASSIFYING: // 动作:根据visionData.type分类,计算目标料箱 fsm->targetBin = ClassifyPart(fsm->visionData.type); // 状态迁移:发送移动指令 SendMoveCommand(fsm->targetBin); fsm->currentState = SYS_MOVING; break; // ... 其他状态处理 case SYS_ERROR: // 错误处理:停止所有动作,等待复位 StopAllActuators(); if (event == EVT_RESET) { fsm->currentState = SYS_IDLE; } break; } }3.2 视觉数据的接收与解析
视觉数据通过Modbus TCP异步到达。我们需要在STM32上实现一个轻量级的Modbus TCP客户端。通常使用一个独立的网络任务或中断来处理。
// 模拟Modbus TCP数据读取任务 void ModbusTask(void) { // 1. 建立连接(略) // 2. 读取保持寄存器(假设视觉结果从寄存器40001开始存放) uint16_t regs[10]; if (ModbusReadHoldRegs(slaveIp, 0, 10, regs) == SUCCESS) { // 3. 解析数据 SystemFSM_t *fsm = GetSystemFSM(); fsm->visionData.type = regs[0]; // 类型码 fsm->visionData.x = ((int32_t)(regs[1] << 16) | regs[2]) / 1000.0f; // 坐标,假设放大1000倍传输 fsm->visionData.y = ((int32_t)(regs[3] << 16) | regs[4]) / 1000.0f; fsm->visionData.angle = (int16_t)regs[5] / 100.0f; // 角度 // 4. 产生事件,通知主状态机 PostSystemEvent(EVT_VISION_DATA_READY); } }3.3 运动控制集成
运动控制(伺服驱动)同样可以通过Modbus RTU(串口)或发送脉冲来控制。使用Modbus RTU的好处是可以通过总线读取驱动器的实时状态(位置、错误码),实现更安全的控制。在SYS_MOVING状态中,控制器发送目标位置,然后等待驱动器返回的“到位”信号作为EVT_MOVE_COMPLETE事件。
4. 开发与调试中的实战陷阱与解决方案
理论设计总是完美的,但现场调试会让你遇到各种意想不到的问题。以下是几个典型的“坑”及其填平方法。
4.1 视觉触发与机械的同步问题
- 问题:相机拍照时,物料还在移动,导致图像模糊;或者拍照位置与实际推料位置存在固定偏差。
- 解决方案:
- 硬触发:使用光电传感器在物料到达拍照固定位置时,同时给相机发硬件触发信号(如上升沿),并给控制器发中断。这是最精准的方式。
- 软件补偿:如果只能异步触发,则需要在视觉结果中引入时间戳。控制器根据当前传送带速度(编码器反馈)和视觉处理延时,动态补偿物料从拍照点到推料点的位移。公式很简单:
补偿距离 = 速度 × (通信延时 + 处理延时 + 机械响应延时)。我们需要在现场用标准块反复校准这个延时参数。
4.2 通信超时与数据完整性
- 问题:Modbus TCP网络偶尔抖动,导致视觉数据读取失败或残缺,状态机卡在
SYS_WAIT_VISION。 - 解决方案:
- 增加重试机制:在Modbus任务中,单次读取失败后,不应立即报错。应设置最多3次重试,每次间隔50ms。
- 心跳包与超时:除了数据通信,让视觉系统定时发送一个“心跳”寄存器值。主控制器监控这个心跳,如果超过2秒未更新,则认为视觉系统离线,主动进入
SYS_ERROR状态并报警。 - 数据校验:在视觉系统发送的数据包中,加入一个简单的校验和(CRC16或求和取模)。主控制器在解析前先校验,失败则丢弃并请求重发。
4.3 状态机的“僵死”与恢复
- 问题:某个意外事件(如执行机构卡住,未返回完成信号)导致状态机无法跳出当前状态,整个生产线停滞。
- 解决方案:
- 状态超时监护:为每一个非空闲状态(如
SYS_MOVING,SYS_SORTING)设置一个最大允许时间。在状态入口处记录时间戳,在主循环中检查,如果超时,则强制产生一个EVT_TIMEOUT事件,跳转到SYS_ERROR状态。 - 错误状态的细化:
SYS_ERROR状态不应只是一个点。我们将其细化为子状态机,包含ERROR_IDLE(等待处理)、ERROR_TRY_RESET(尝试复位执行器)、ERROR_NEED_MANUAL(需要人工干预)。并可通过HMI查看当前具体的错误码和推荐操作。
- 状态超时监护:为每一个非空闲状态(如
4.4 光照变化与视觉误判
- 问题:车间环境光变化(如早晚阳光、其他设备灯光干扰)导致视觉识别率在一天内波动。
- 解决方案:
- 光源闭环控制:选用自带光强反馈的智能光源,或通过相机采集图像的灰度均值,通过PID算法动态调节光源亮度,使打光环境恒定。
- 多特征融合与机器学习:不要只依赖一个视觉特征(如轮廓)。结合颜色、纹理、甚至简单的深度学习分类(如将Vision Transformer轻量化后部署在智能相机上)。对于传统算法,定期(如每4小时)让系统自动运行一次“标定”程序,采集标准样本图像,更新匹配模板的阈值参数。
5. 性能优化与扩展思考
当基本功能跑通后,我们可以从以下几个维度让系统变得更强大、更智能。
5.1 提升节拍:并行处理与流水线
分析状态机的时间线,WAIT_FOR_VISION和CLASSIFYING阶段主要是等待和计算,而MOVE_TO_TARGET和EXECUTE_SORTING是机械运动时间。为了提升效率(更高节拍),可以采用流水线思想:
- 当第一个物料在
MOVE_TO_TARGET时,第二个物料已经可以进入WAIT_FOR_VISION阶段。 - 这意味着需要两个(或更多)独立的物理工位,以及更复杂的状态机(可能演变为并行多个实例或更高级的Petri网模型)。同时,机械设计上要避免干涉。
5.2 引入更高阶的视觉模型
对于更复杂的分类,如检测元件表面的细微划痕、印刷字符的完整性(联想到Completeness of Vision这个概念在质量检测上的应用),传统的Blob分析或模板匹配可能力不从心。此时可以考虑:
- 使用开源的深度学习框架(如TensorFlow Lite Micro)在嵌入式视觉模块上部署一个轻量级卷积神经网络(CNN)或Vision Mamba这类新架构的模型进行缺陷分类。
- 将训练好的模型集成到类似Vision Master这样的图形化工具中,通过拖拉拽的方式部署,降低开发门槛。
5.3 与上层系统集成:迈向工业4.0
单个分拣站是信息孤岛。通过为STM32增加以太网或无线模块,我们可以:
- 上报数据:将产量、合格率、设备综合效率(OEE)、错误日志等数据,通过MQTT或OPC UA协议上传到工厂的MES(制造执行系统)或云平台。
- 接受调度:从上层系统接收生产订单,动态切换分拣的物料类型和规则,实现柔性生产。
- 远程维护:支持远程查看状态、更新程序、甚至进行简单的调试,减少现场维护时间。
这个由视觉和状态机驱动的工业分拣自动化项目,从明确的需求定义,到硬件选型、软件架构设计,再到现场调试与优化,是一个典型的软硬件深度融合的过程。它证明了,即使在不使用大型PLC和工控机的情况下,通过合理的架构设计(清晰的视觉-控制-执行分层)和核心范式(FSM),用微控制器也能构建出稳定、高效、可维护的工业自动化系统。最关键的是,这种方案带来了极大的灵活性——无论是更换视觉算法,还是调整分拣逻辑,你只需要修改或扩展那个定义清晰的状态机,而无需重写整个混乱的控制流程。