🤖 真实项目实战

机器人上下料数据采集方案

汇川Easy320 PLC + 新松多可协作机器人,Modbus TCP通讯,10x12料盘管理,首件/周期抽检逻辑,C# WPF上位机实时监控

⚙️ 汇川Easy320 PLC 主控逻辑
🤖 新松多可机器人 执行机构
📡 Modbus TCP 通讯协议
🖥️ 上位机(C# WPF) 数据采集与显示
💾 TDengine 数据存储
🤖 设备:新松多可协作机器人 ⚙️ PLC:汇川Easy320 📋 料盘:10×12 = 120位 🔄 通讯:Modbus TCP

01 项目背景与需求

场景描述

某机加工车间,1台CNC加工中心配1台新松多可协作机器人做上下料。工件放在10×12的料盘上(共120个位置),机器人从料盘取毛坯放到CNC加工,加工完成后取成品放回料盘。需要监控整个生产过程,统计产量,管理料盘状态,实现首件和周期抽检。

核心需求

📋
料盘管理
10×12料盘状态实时显示,空/有料/已加工/异常一目了然
🔍
抽检逻辑
首件必检+每10件周期抽检,抽检参数可配置,不用改PLC程序
📊
产量统计
实时产量、节拍分析、OEE计算,班次/日/周/月报表
🚨
报警管理
机器人异常/CNC报警/料盘满/缺料,实时报警+历史追溯

02 系统架构

PLC主控 + 机器人执行 + 上位机监控,三层架构,Modbus TCP统一通讯

01
⚙️
主控PLC
汇川Easy320
料盘管理、工位状态、首件/抽检逻辑、与机器人握手信号,Modbus TCP Server开放寄存器
→
02
🤖
机器人
新松多可协作
上下料执行,通过IO信号与PLC握手(取料/放料/完成/异常),支持拖拽示教和碰撞检测
→
03
📡
通讯层
Modbus TCP
PLC作为Server,上位机作为Client读写寄存器,10x12料盘状态、产量、报警、参数全部映射到寄存器地址
→
04
🖥️
上位机
C# WPF MVVM
实时数据采集(100ms刷新)、料盘可视化、产量统计、报警管理、参数设置、报表导出,MVVM架构便于维护
→
05
💾
数据存储
TDengine
生产数据时序存储(每班次产量/节拍/报警),支持OEE分析和历史追溯,数据保留3年
💡 架构设计要点:
  • PLC做主控,机器人做执行:所有逻辑判断(料盘管理/抽检/报警)都在PLC里,机器人只执行PLC的指令(取料/放料/移动)。这样换机器人不用改逻辑,换PLC程序结构也清晰
  • 握手信号用三段式:置位请求→等待应答→复位请求,不用脉冲信号(容易丢)。每个信号加超时检测,超时报警停机
  • 寄存器映射提前规划:料盘状态/设备状态/产量/报警/参数,每类一段连续地址,写在Excel里PLC和上位机共用。避免后期加点位地址乱掉
  • 上位机不做实时控制:上位机只做数据采集和显示,不参与控制逻辑。上位机挂了不影响生产,重启后自动重连恢复数据

03 部署要点(关键配置)

01

PLC寄存器规划

提前规划好Modbus寄存器映射表:40001-40120料盘状态、40121-40150设备状态、40151-40180产量计数、40181-40200报警代码、40201-40250参数配置。写在Excel里,PLC和上位机共用同一份表,避免地址不一致

02

PLC握手程序

实现"置位-等待-复位"三段式握手,每个握手信号加超时检测(5秒),超时触发报警并停机。用状态机组织主逻辑:待机/运行/首检/周检/异常,状态转移条件写在单独的转移表中,便于维护

03

机器人程序

机器人程序用模块化:取料子程序(参数:料盘行列号)、放料子程序(参数:工位号)、移动子程序(参数:目标坐标)。主程序只做状态判断和子程序调用。坐标用相对坐标系(基于料盘原点),换型时只改原点坐标

04

上位机架构

WPF + MVVM架构:Model层(数据模型+Modbus通讯)、ViewModel层(业务逻辑+数据转换)、View层(界面展示)。Modbus通讯用第三方库(NModbus4或EasyModbus),封装成独立的通讯服务类,支持断线自动重连

05

料盘可视化

用ItemsControl+DataTemplate渲染10x12料盘格子,每个格子绑定状态(空/有料/已加工/异常),用颜色区分。支持点击格子查看详情(该位置产品信息/加工时间/操作员)。用Canvas做绝对定位可以更精确控制格子间距和大小

06

数据存储与报表

生产数据(产量/节拍/报警)通过MQTT或REST API写入TDengine,上位机本地也存一份SQLite做离线缓存。报表用EPPlus生成Excel,支持日报/周报/月报,包含产量统计、OEE计算、报警汇总、节拍分析。每天8点自动生成前一天报表并邮件发送

04 踩过的坑(真实问题与解决方案)

机器人上下料项目最容易出问题的就是通讯握手和料盘管理,这里是真实踩过的5个坑

坑 01 PLC和机器人握手信号偶发丢失,机器人停在半空中不动
原因: 用普通线圈(M线圈)做握手信号,PLC扫描周期和机器人响应周期不同步,信号持续时间太短(1个扫描周期约1ms)机器人没捕捉到
解决: 改用"置位-等待-复位"三段式握手:PLC置位请求信号→等待机器人应答信号→收到应答后复位请求→机器人收到请求复位后复位应答。每个信号至少保持2个扫描周期,加超时报警(5秒无应答触发异常)
坑 02 10x12料盘状态在上位机显示偶尔闪烁(同一位置一会儿有料一会儿没料)
原因: 上位机用Modbus TCP分批读取120个料位状态(每批20个寄存器,分6批),批次之间有时间差(约50ms),期间PLC更新了数据导致前后批次不一致
解决: 把120个料位状态连续映射到一段寄存器(40001-40120),上位机一次性读取120个寄存器(Modbus TCP单次最多125个寄存器,足够),保证数据一致性。如果超过125个,用"快照"机制:PLC在读取前先把数据复制到快照区,上位机读快照区
坑 03 首件抽检和周期抽检逻辑复杂,PLC程序越写越乱,改一个逻辑要翻半天
原因: 所有逻辑(首件/每10件/换班/换型)都写在一个主程序块里,用大量定时器和计数器嵌套,没有结构化
解决: 用状态机模式重构:定义状态(待机/运行/首检等待/首检中/周期检等待/周期检中/异常),每个状态一个子程序块,状态转移条件清晰。抽检参数(首件数量/周期数量/超时时间)全部存在保持寄存器,上位机可配置,不用改PLC程序
坑 04 上位机采集100ms刷新,运行一段时间后界面卡顿,数据延迟越来越大
原因: WPF界面直接在采集线程更新UI控件,采集线程被UI渲染阻塞;且每个点位都触发PropertyChanged,120个料位+20个状态=140次UI更新/100ms,UI线程忙不过来
解决: 采集线程只更新数据模型(不碰UI),用批量更新:100ms内所有点位更新完后一次性触发UI刷新(而不是每个点位单独触发);用VirtualizingStackPanel虚拟化料盘列表(120个格子不需要全部渲染);采集线程和UI线程用Dispatcher.BeginInvoke异步更新
坑 05 换型时(不同产品料盘布局不同),料盘坐标映射经常搞错,机器人抓错位置
原因: 料盘坐标(行列→世界坐标)的换算公式写死在PLC里,换型时要改程序;且行列编号方向(从左到右还是从右到左)没有统一约定
解决: 把料盘参数(行数/列数/间距/起始坐标/行列方向/旋转角度)全部存在PLC保持寄存器,上位机做可视化配置界面(拖拽设置第一个点位置,自动计算其他点),换型时在上位机选择对应配方一键下载。加坐标校验功能:配置完成后机器人逐个点走一遍,人工确认后才保存

05 关键代码片段

三段式握手(PLC结构化文本示例)

// 请求机器人取料
IF 取料请求 = FALSE AND 取料应答 = FALSE AND 需要取料 THEN
    取料请求 := TRUE;          // 1. 置位请求
    取料超时计时 := 0;
END_IF;

// 等待应答
IF 取料请求 = TRUE AND 取料应答 = FALSE THEN
    取料超时计时 := 取料超时计时 + 1;
    IF 取料超时计时 > 500 THEN  // 5秒超时(10ms扫描)
        报警_机器人取料超时 := TRUE;
        系统状态 := 异常;
    END_IF;
END_IF;

// 收到应答,复位请求
IF 取料请求 = TRUE AND 取料应答 = TRUE THEN
    取料请求 := FALSE;         // 3. 复位请求
END_IF;

// 机器人复位应答后,完成一次取料
IF 取料请求 = FALSE AND 取料应答 = TRUE THEN
    取料应答 := FALSE;
    当前料位 := 当前料位 + 1;
    产量计数 := 产量计数 + 1;
END_IF;

Modbus批量读取(C# WPF示例)

// 一次性读取120个料盘状态寄存器(40001-40120)
// 保证数据一致性,不会出现前后批次时间差
public async Task<ushort[]> ReadTrayStatusAsync()
{
    if (_client == null || !_client.Connected)
    {
        await ReconnectAsync();
    }
    try
    {
        // Modbus TCP单次最多读125个寄存器,120个刚好一次读完
        var result = await _client.ReadHoldingRegistersAsync(
            slaveAddress: 1,
            startAddress: 0,      // 40001对应地址0
            numberOfPoints: 120); // 一次读120个
        return result;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "读取料盘状态失败");
        await ReconnectAsync();
        throw;
    }
}

06 相关软件与工具

需要机器人上下料或PLC通讯方案?

丁丁做过汇川PLC+新松机器人的真实项目,熟悉Modbus TCP通讯、料盘管理、抽检逻辑、WPF上位机开发。可以帮你做方案设计、PLC程序、上位机开发、现场调试。