当前位置:首页 > 工业控制 > 工业控制
[导读]工业产线最怕两件事:网络一断数据空白、云往返延迟让告警慢半拍。边缘计算节点不是“把MCU数据转发到服务器”,而是把计数、良率、节拍、班产这些统计在网关/工控机本地算完,云只拿汇总结果。 架构本质是三层解耦:采集线程只往本地缓冲写,统计任务周期聚合,上传任务可断可续——不上云也能跑完整班。


工业产线最怕两件事:网络一断数据空白、云往返延迟让告警慢半拍。边缘计算节点不是“把MCU数据转发到服务器”,而是把计数、良率、节拍、班产这些统计在网关/工控机本地算完,云只拿汇总结果。 架构本质是三层解耦:采集线程只往本地缓冲写,统计任务周期聚合,上传任务可断可续——不上云也能跑完整班。

一、边缘节点职责边界

现场数据源是PLC、Modbus从站、扫码枪、光电计数、OPC UA;边缘节点干四件事:

协议归一:Modbus/TCP、RTU、CANopen统一成内部事件

本地过滤:重复脉冲、抖动误触发先消掉

实时统计:产量/良品/不良/运行时间/节拍

存储缓存:断网落本地,恢复后续传

规则很简单:原始高频数据不留云,只留聚合结果。1秒级明细存本地几小时,分钟级汇总才往上送。

二、统计结构体:以工位为单位

别用全局变量散着加,按station建表:

typedef struct {

   uint8_t  station;

   uint32_t total;        // 总产出

   uint32_t good;         // 良品

   uint32_t bad;          // 不良

   uint32_t run_ms;       // 本班运行时间

   uint32_t stop_ms;      // 停机时间

   uint32_t cyc_last_us;  // 上次产品通过时间戳

   float    cyc_avg_us;   // 平均节拍

   uint32_t last_seq;     // 断点续传序号

} stat_t;


stat_t st[16];

良率、性能稼动率都是派生值,现场不算也行,HMI本地读结构体直接显示。

三、采集回调:只计数不联网

光电/编码器/PLC完成信号统一进事件函数,去抖后更新计数:

void on_product_pulse(uint8_t ch, uint8_t is_good){

   stat_t*s = &st[ch];

   uint32_t now = tick_us();

   if(s->cyc_last_us){

       uint32_t dt = now - s->cyc_last_us;

       /* 滑动平均,滤掉偶发粘连 */

       s->cyc_avg_us = s->cyc_avg_us*0.8f + dt*0.2f;

   }

   s->cyc_last_us = now;


   s->total++;

   if(is_good) s->good++;

   else        s->bad++;


   stat_mark_dirty(ch);   // 标记待落盘,不在这里写Flash

}


void on_run_state(uint8_t ch, uint8_t running){

   stat_t*s = &st[ch];

   if(running) s->run_ms += tick_ms()-s->last_t;

   else       s->stop_ms+= tick_ms()-s->last_t;

   s->last_t = tick_ms();

}

采集路径零分配、零文件系统调用,绝不在中断里碰SD卡。

四、本地聚合任务:1秒/1分钟滚动

单独任务跑聚合,算班产、良率、节拍:

void stat_aggregate_1s(void){

   for(int i=0;i<16;i++){

       stat_t*s=&st[i];

       float yld = s->total? (float)s->good/s->total*100.0f : 0;

       local_publish(s->station, s->total, yld,

                     s->cyc_avg_us/1000.0f);

   }

}

需要OEE再补:可用率=run/(run+stop),性能=实际节拍/理论节拍。 但边缘节点默认只算到“班产+良率+节拍”就够产线看板用了。

五、本地存储:RAM环形+非易失落盘

实时计数在RAM,掉电会丢;关键的是“已汇总结果”和“待补传记录”要落盘。

小数据:FRAM/EEPROM存班统计快照

大数据:LittleFS/SPIFFS存JSON汇总

断网缓存:SQLite或自定义环形扇区

typedef struct {

   uint32_t seq;

   uint32_t ts;

   uint8_t  station;

   uint16_t total;

   uint16_t good;

   uint8_t  sync;     // 0待传 1已传

} rec_t;


rec_t cache[256];

int c_w, c_r;


void stat_flush_to_disk(void){

   rec_t*r=&cache[c_w];

   r->seq = ++st[0].last_seq;

   r->ts  = rtc_ms();

   r->total = st[0].total; r->good=st[0].good;

   r->sync=0;

   cache_write_sector(r);

   c_w=(c_w+1)&255;

}

写盘频率别太高,1秒~1分钟一条汇总,Flash寿命和带宽都够。

六、断点续传:按seq补,不重不漏

上传线程和采集线程解耦,网络恢复后从最老未确认记录开始发:

void upload_task(void){

   if(!net_ok()) return;

   while(c_r != c_w){

       rec_t*r=&cache[c_r];

       if(r->sync) { c_r=(c_r+1)&255; continue; }

       if(mes_post(r)==0){

           r->sync=1;

           cache_mark_sync(r->seq);

           c_r=(c_r+1)&255;

       }else break;   // 网络又断,留原地

   }

}

要点:

每条带seq+时间戳,云端按seq去重

只有收到ACK才标sync,否则重发

缓冲满按工位优先级淘汰老数据

实时告警(停机/不良突增)可越过缓存直发

七、落坑清单

每脉冲写一次Flash→擦写寿命耗尽

采集ISR里HTTP上传→阻塞丢脉冲

断网不落盘→恢复后班产空白

续传从头发→云端重复计数

不带seq→网络抖动重复插入

原始数据全传云→带宽被脉冲流打满

良率用全厂平均→工序问题被掩盖

节拍用理论值→性能损失算不出来

HMI直接读全局变量→多任务竞态

上电不清last_t→运行时间跳变

八、落地顺序

定义station维度统计结构体,采集只改RAM

脉冲/完成信号去抖后计数,绝不联网

1s任务算班产、良率、平均节拍

汇总记录写LittleFS/SQLite,带seq+ts

网络线程独立,断网沉淀本地

恢复后按seq顺序补传,ACK才清sync

HMI读本地统计,不依赖云端在线

关键告警可越级直发,普通数据批量补

边缘节点做生产统计的核心不是“会算数”,是采集和上传解耦:高频事件在RAM里聚合,汇总结果才落盘,网络只是可选通道。 断不断网都不影响现场计数和看板;真要回传MES,也是带seq的分钟级汇总,不是原始脉冲流。这样工业现场哪怕4G断几小时,恢复后数据按序补齐,班产、良率、节拍都不会漂——云端在这里只是备份,不是主计算。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭