• 借助PLC-Recorder,汇川中型PLC(AM、AC系列,CODESYS平台)2ms高速采集的方法


    高速数据采集要保证速度,也要保证时刻的准确性。在windows系统里,时间稳定性是个很难的问题。如果PLC发送的数据里带有时间信息,则可以由PLC来保证采样周期的稳定性。

    从V2.12版本开始,PLC-Recorder软件可以处理发送电文里的时间戳,有网友用0.24ms的速度外发,软件也能够稳定接收并精确确定数据的时刻。

    本文向大家展示一下汇川CODESYS平台PLC(AM等系列)通过UDP快速通讯的实现方法。

    一、测试条件

    下面用AM401实现带有时间戳的高速数据采集,测试条件如下:

    • PLC的主任务设置成1ms的循环(最小只能设置成1ms。测试发现设置为“惯性滑行”时,实际周期为3ms)。
    • 通讯协议:UDP(目前只有该协议,在高速模式下才支持时间戳)。
    • 编程软件和系统:InoProShop(基于CODESYS V3平台)
    • PLC的系统版本:3.5.11.10,IP地址:192.168.0.1
    • 微型工控机(Intel® Celeron J1900 2.0GHz四核低功耗处理器) 4核 4G内存,SSD硬盘,无风扇,WIN10系统,无其他大型软件。IP地址:192.168.0.100。

    二、测试结论

    本次测试采用了连续循环,每两个周期发送一次(上升沿触发)。实测发送周期:2ms

    三、PLC的发送程序

    1、时间戳

    通过读取PLC的启动后的运行时间(精确到纳秒,本软件支持微秒和毫秒时间戳)来获得时间戳,输出恰好uint32类型(PLC里是udint),此处选择微秒为单位,从0到4_294_967_295之间递增,自然翻转(自动归零)。70分钟翻转一次。时间戳是个时间差值,PLC-Recorder在开始记录时,会将首个时间戳与计算机的当前时间进行比较(对时),后续就用相对时间进行计算,并自动处理翻转的问题。因此,PLC不需要保证绝对时钟的准确性,只要相对稳定即可。

    2、自定义的数据结构

    本试验用联合数据类型(Union),结合结构变量解决结构体变量转字节数组的问题,详细参考文章。相关数据结构如下:

    1. TYPE union_udint :
    2. UNION
    3. Value:UDINT;
    4. Bytes:ARRAY[0..3] OF BYTE;
    5. END_UNION
    6. END_TYPE
    7. TYPE union_uint :
    8. UNION
    9. Value:UINT;
    10. Bytes:ARRAY[0..1] OF BYTE;
    11. END_UNION
    12. END_TYPE
    13. TYPE union_real :
    14. UNION
    15. Value:REAL;
    16. Bytes:ARRAY[0..3] OF BYTE;
    17. END_UNION
    18. END_TYPE
    19. TYPE union_lreal :
    20. UNION
    21. Value:LREAL;
    22. Bytes:ARRAY[0..7] OF BYTE;
    23. END_UNION
    24. END_TYPE
    25. TYPE DUT_SEND_DATA:
    26. STRUCT
    27. STAMP :union_udint;//单位为微秒的时间戳
    28. data1:union_uint;//UInt类型的数值
    29. data2:union_real;//浮点数类型的数值
    30. data3:union_lreal;//双精度类型的数值
    31. END_STRUCT
    32. END_TYPE

    3、主程序的局部变量

    1. VAR
    2. UDP_Peer_1 :UDP_Peer;
    3. UDP_Send_1:UDP_Send;
    4. ib_Connect_Enable: BOOL:=TRUE;//连接允许
    5. PLC_IpAddrLocal:STRING:='192.168.0.1' ;//PIC本地IP地址,此处用于计算机仿真,实际请参考PLC配置进行修改。
    6. PLC_PortLocal:UINT:=1217;//PIC本地端口号
    7. vb_dConnection: __XWORD;//UDP通讯句柄
    8. ob_Connect_Done: BOOL;//连接完成
    9. ob_Connect_Busy: BOOL;//正在连接
    10. ob_Connect_Error: BOOL;//连接出错
    11. ob_Connect_Actived: BOOL;//连接成功
    12. ob_Connect_ErrorID: DWORD;//连接错误信息
    13. ib_Send_Enabled: BOOL:=TRUE;//发送允许
    14. isi_ServerIP: STRING:='192.168.0.100' ;//服务器IP地址,此处用于计算机仿真,实际请参考PLC配置进行修改。;
    15. isi_ServerPort: UINT:=5010; // 服务器端口号
    16. id_SendLength: UINT:=200;//发送长度(字节)
    17. id_SendBuffer:ARRAY[0..199] OF BYTE;//发送缓冲器。
    18. vd_SendTimeOut: UDINT:=500000;//超时长度us
    19. ob_SendDone: BOOL;
    20. ob_SendBusy: BOOL;
    21. ob_SendErrorID: DWORD;
    22. sendData:DUT_SEND_DATA;
    23. clockus:ULINT;
    24. pArray:UINT;
    25. i:UINT;
    26. sendPulse:BOOL;
    27. END_VAR

    4、PLC程序

    1. GetSystemTime(uliTimeUs=>clockus);//获取运行时间(微秒为单位)
    2. sendPulse:=NOT(sendPulse);//发送脉冲,每周期跳变一次
    3. sendData.STAMP.Value:=ULINT_TO_UDINT(clockus);//截取低4字节的值。
    4. //周期计数
    5. IF sendPulse THEN
    6. sendData.data1.Value:=sendData.data1.Value+1;
    7. IF UINT_TO_INT( sendData.data1.Value) >=30000 THEN
    8. sendData.data1.Value:=0;
    9. END_IF
    10. sendData.data3.Value:=UINT_TO_LREAL(sendData.data1.Value);
    11. END_IF
    12. //数据打包到发送缓冲器,直接操作字节数组。
    13. pArray:=0;
    14. FOR i:=0 TO SIZEOF(sendData.STAMP.Bytes)-1 BY 1 DO
    15. id_SendBuffer[pArray]:=sendData.STAMP.Bytes[i];
    16. pArray:=pArray+1;
    17. END_FOR
    18. FOR i:=0 TO SIZEOF(sendData.data1.Bytes)-1 BY 1 DO
    19. id_SendBuffer[pArray]:=sendData.data1.Bytes[i];
    20. pArray:=pArray+1;
    21. END_FOR
    22. FOR i:=0 TO SIZEOF(sendData.data2.Bytes)-1 BY 1 DO
    23. id_SendBuffer[pArray]:=sendData.data2.Bytes[i];
    24. pArray:=pArray+1;
    25. END_FOR
    26. FOR i:=0 TO SIZEOF(sendData.data3.Bytes)-1 BY 1 DO
    27. id_SendBuffer[pArray]:=sendData.data3.Bytes[i];
    28. pArray:=pArray+1;
    29. END_FOR
    30. //UDP通讯链路创建
    31. UDP_Peer_1(
    32. xEnable:=ib_Connect_Enable,
    33. strIpAddrLocal:=PLC_IpAddrLocal,
    34. uiPortLocal:=PLC_PortLocal,
    35. xDone=>ob_Connect_Done,
    36. xBusy=>ob_Connect_Busy,
    37. xError=>ob_Connect_Error,
    38. dwErrorID=>ob_Connect_ErrorID,
    39. xActive=>ob_Connect_Actived,
    40. hPeer=>vb_dConnection
    41. );
    42. //UDP发送指令
    43. UDP_Send_1(
    44. xExecute:=ob_Connect_Actived AND vb_dConnection<>0 AND ib_Send_Enabled AND sendPulse,
    45. hPeer:=vb_dConnection,
    46. strIpAddrDst:=isi_ServerIP,
    47. uiPortDst:=isi_ServerPort,
    48. uiSize:=id_SendLength,
    49. pbyData:=ADR(id_SendBuffer),
    50. udiTimeOut:=vd_SendTimeOut,
    51. xDone=> ob_SendDone,
    52. xBusy=>ob_SendBusy,
    53. dwErrorID=>ob_SendErrorID
    54. );

    四、PLC-Recorder侧的通讯设置

    请用帕姆齐设备类型,目前,仅该类型支持时间戳功能,并选择时间戳单位为us(PLC-Recorder V2.12.7开始支持该功能)。需要配置来源的IP地址及本机收听的端口号。

    五、PLC-Recorder的通道配置

    此处虽然配置了采集周期,但在高速模式下不再使用该周期,以收到信息的时刻为准(以下是PLC-Recorder V3的界面,与V2稍微不同,请注意)。

    六、PLC-Recorder的变量配置

    从最后一个变量的起始地址和变量长度可以确定该通道的通讯电文的长度。对于TCP类型的连接,电文长度需要通过最后变量进行确定(下例子看出电文长度为200字节)。

    对于UDP类型的通讯,UDP是按照完整报文进行传输的,可以自动获取长度信息,因此,不需要关注最后变量。

    变量配置时,不需要定义所有的变量,仅需要定义自己关注的变量即可。

    起始地址为0的变量就是PLC里定义的时间戳。

    七、记录数据的情况

    这是用离线分析软件Ana打开的历史数据文件(分析时长:0.5小时,采集次数96万)。从左侧的统计数据可以看出,平均采集周期是2ms(与PLC1ms的周期对应)。从右侧的波形和标尺可以看出,点距非常均匀。

    八、小结

    汇川的中型PLC是基于CODESYS平台,UDP通讯程序可以供其他类似系统借鉴。

    采集的速度越快,需要的技术越复杂,代价也越大。PLC-Recorder的主动采集模式,基本只需要在PLC-Recorder里配置变量,不需要在PLC做什么复杂工作,这种方式很便捷,但是速度也有限(最快20ms)。高速模式,就需要在PLC里配置通讯,组织数据,然后调用通讯语句,才能够实现,因此,对于PLC工程师也有了一点要求。

    高速模式采用标准以太网通讯协议,这也是大部分PLC都具备的能力,因此,可以被广泛用于快速数据采集。

    2023-10-8

  • 相关阅读:
    [ubuntu][原创]ubuntu18.04安装微信最简单方法2022年
    Android Jetpack系列(一)起始篇:Jetpack 的前世今生
    02【SpringMVC的工作流程】
    Linux——MySQL 的 MGR 集群和Redis的编译安装
    图解Kicad导入元器件封装
    【KDD20】多变量时间序列异常检测算法之USAD:对抗性训练AE
    计算机毕业设计(附源码)python志愿者招募系统
    在绩效评估中使用 360 反馈
    案例分享|金融业数据运营运维一体化建设
    dubbo zookeerper
  • 原文地址:https://blog.csdn.net/chengjl8/article/details/133678751