MES的另一个常见应用是过程数据的上传。
车间现场的设备会产生大量过程数据,需要上传到MES,主要基于以下两个考虑:
1、 过程数据经过整理,可以用于统计分析。
2、 结果数据上传到MES后,MES会根据结果来判断产品的后续工序。
通常来说,不同行业有自己的专属工具,特别是自动测试台架有很强的定制性,软件也往往是高度定制的。
下面我尝试以实例说明,来探讨过程数据上传的通用设计。
某测试台架产生测试数据后,将关键数据写入PLC,上传到MES,MES根据传入数据的结果来决定将产品送入包装工位还是返修工位。
大致的设计思路是:
1、 MES将PLC的原始数据按照某种规则转换成标准的过程数据结构。
2、 MES判断结果,并执行对应的业务流程。
比如说,PLC的数据结构是:
字段 |
起始位 |
长度 |
示例 |
说明 |
String Length |
0 |
3 |
011 |
PLC有效字符长度11 |
Result |
3 |
1 |
P |
测试结果,P表示成功,其它值表示失败 |
Item1 |
4 |
2 |
20 |
测试项1的值 |
Item2 |
6 |
3 |
120 |
测试项2的值 |
String End |
9 |
2 |
OK |
结束字符 |
现在我们在数据库中建一个表来表达通用的数据结构:
字段名 |
数据类型 |
说明 |
STATION |
VARCHAR2(20 BYTE) |
工位 |
ITEMNO |
NUMBER(2,0) |
参数序列 |
ITEMNAME |
VARCHAR2(200 BYTE) |
参数名 |
ITEMLENGTH |
NUMBER(3,0) |
参数长度 |
ITEMUNIT |
VARCHAR2(20 BYTE) |
参数单位 |
STATUSMARK |
NUMBER(1,0) |
值为1表示此参数用于判定测试结果 |
STATUSVALUE |
VARCHAR2(20 BYTE) |
判定测试通过的有效数据 |
那么此PLC数据结构在此表中这样定义:
STATION |
ITEMNO |
ITEMNAME |
ITEMLENGTH |
ITEMUNIT |
STATUSMARK |
STATUSVALUE |
1234 |
1 |
Test Status |
1 |
1 |
P |
|
1234 |
2 |
Item1 |
2 |
G |
||
1234 |
3 |
Item2 |
3 |
MM |
有了这个结构作为参照,当我们接收到PLC的原始数据后,我们就可以解析出测试结果,以及测试项1、测试项2的值。
附加上产品序列号、测试工位、测试时间、测试人员这些基本数据,我们就得到完整的测试过程数据。
下面我们进一步就可以把过程数据保存到数据库中。
在数据库中建立一个主表,一个从表,其中主表保存产品序列号、测试工位、测试时间、测试人员、测试结果。从表保存所有测试项的名称、值和单位。
在数据库中再建立一个触发器,监控主表的创建,一旦有新的数据,则立即查询测试结果,根据结果的不同来执行对应的业务逻辑。
下面是实现数据解析及结果处理的示例代码(Oracel数据库):
DECLARE uploadstring VARCHAR2(2000); leftstring VARCHAR2(2000); itemname VARCHAR2(20); itemvalue VARCHAR2(2000); itemunit VARCHAR2(2000); itemlength INTEGER; statusmark VARCHAR2(1); statusvalue VARCHAR2(1); passfail INTEGER;
CURSOR mycur IS SELECT t.itemno, t.itemname, t.itemlength, t.itemunit, t.statusmark, t.statusvalue FROM t -- à t是定义结构的表 WHERE t.station = I_STATION ORDER BY t.itemno;
BEGIN
uploadstring := I_UPLOADSTRING; leftstring := uploadstring; itemname := 0; itemvalue := uploadstring; itemunit := ''; itemlength := 0; statusmark := 0; statusvalue := ''; passfail := 1;
-- 1. get all items 查询得到所有数据 FOR rec IN mycur LOOP itemname := rec.itemname; itemlength := rec.itemlength; statusmark := rec.statusmark; statusvalue := rec.statusvalue; itemvalue := SUBSTR(leftstring, 1, itemlength); -- 1.1 check test status mark 找到判断结果的参数 IF statusmark = 1 THEN if itemvalue = statusvalue THEN passfail := 1; ELSE passfail := 0; END IF; END IF; leftstring := SUBSTR(leftstring, length(itemvalue)+1,1000);
END LOOP;
-- 1.2 add test data master 插入数据到主表 SP_INS_TESTDATAMST ( I_ESN, I_STATION, I_TIME, I_OPERATOR, passfail, O_MSTID -- à 主表流水号 ); COMMIT;
-- 2 add test data detail插入数据到从表 leftstring := uploadstring; FOR rec2 IN mycur LOOP itemname := rec2.itemname; itemlength := rec2.itemlength; statusmark := rec2.statusmark; statusvalue := rec2.statusvalue; itemunit := rec2.itemunit; itemvalue := SUBSTR(leftstring, 1, itemlength); -- 1.1 check NOT test status mark IF statusmark = 0 THEN SP_INS_TESTDET ( O_MSTID, itemname, itemvalue, itemunit ); COMMIT;
END IF; leftstring := SUBSTR(leftstring, length(itemvalue)+1,1000); END LOOP;
END; |