TwinCAT3中字节数组转LREAL(double)及数组切片索引实现方法咨询
问题1:动态数组区间语法报错的解决
TwinCAT 结构化文本不支持使用变量作为上下限的动态数组切片写法[a..b],切片的上下限必须为编译期常量。不需要对原数组做切片,有两种更高效的实现方式:
- 直接通过
DataReceived[i + 固定偏移量 + 字节序号]的方式逐个访问指定位置的字节 - 调用系统函数
MEMCPY,从原数组的指定偏移地址复制8个字节到临时缓冲区,无需手动逐个取值
问题2:字节数组转LREAL的实现
你之前用BYTEARR_TO_STRING转字符串再转LREAL的方法是完全错误的,这个函数是用来把ASCII编码的字节数组转成字符串,不能处理二进制数值。正确实现方式如下:
- 首先定义一个共用体类型,匹配8字节LREAL的内存结构:
TYPE BYTE8_LREAL : UNION byte_buf : ARRAY[0..7] OF BYTE; // 8个字节缓冲区 lreal_val : LREAL; // 对应解析后的双精度浮点数 END_UNION END_TYPE
- 处理字节序问题:UR机器人返回的报文是大端序(对应Python代码里
struct.unpack('>d')的>标识),而TwinCAT运行的x86/x64平台是小端序,所以需要把读取到的8个字节反转顺序后再填入共用体,才能得到正确的数值。
完整修改后的功能块代码
功能块定义部分
FUNCTION_BLOCK DataEncoding VAR_INPUT DataReceived: ARRAY[0..1115] OF BYTE; END_VAR VAR_OUTPUT moment: ARRAY[0..5] OF LREAL := [6(0.0)]; joint_pos: ARRAY[0..5] OF LREAL := [6(0.0)]; joint_vel: ARRAY[0..5] OF LREAL := [6(0.0)]; tcp_pos: ARRAY[0..5] OF LREAL := [6(0.0)]; tcp_vel: ARRAY[0..5] OF LREAL := [6(0.0)]; tcp_force: ARRAY[0..5] OF LREAL := [6(0.0)]; state: LREAL := 0.0; time_new: LREAL := 0.0; END_VAR VAR i: INT; conv_union: BYTE8_LREAL; // 转换用共用体 j: INT; END_VAR
功能块主体逻辑部分
// 循环上限设为1112,避免i+3越界访问数组 FOR i := 0 TO 1112 BY 1 DO // 匹配报文头0x00 0x00 0x04 0x5C(十进制92) IF DataReceived[i] = 0 AND DataReceived[i+1] = 0 AND DataReceived[i+2] = 4 AND DataReceived[i+3] = 92 THEN // 解析moment数组,偏移从204开始,每个值占8字节 FOR j := 0 TO 5 DO // 复制8个字节到共用体缓冲区 MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 204 + j*8]), 8); // 反转字节序适配大端报文 conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; moment[j] := conv_union.lreal_val; END_FOR; // 解析joint_pos数组,偏移从252开始 FOR j := 0 TO 5 DO MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 252 + j*8]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; joint_pos[j] := conv_union.lreal_val; END_FOR; // 解析joint_vel数组,偏移从300开始 FOR j := 0 TO 5 DO MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 300 + j*8]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; joint_vel[j] := conv_union.lreal_val; END_FOR; // 解析tcp_pos数组,偏移从444开始 FOR j := 0 TO 5 DO MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 444 + j*8]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; tcp_pos[j] := conv_union.lreal_val; END_FOR; // 解析tcp_vel数组,偏移从492开始 FOR j := 0 TO 5 DO MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 492 + j*8]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; tcp_vel[j] := conv_union.lreal_val; END_FOR; // 解析tcp_force数组,偏移从540开始 FOR j := 0 TO 5 DO MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 540 + j*8]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; tcp_force[j] := conv_union.lreal_val; END_FOR; // 解析state,偏移1052 MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 1052]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; state := conv_union.lreal_val; // 解析time_new,偏移4 MEMCPY(ADR(conv_union.byte_buf), ADR(DataReceived[i + 4]), 8); conv_union.byte_buf := [conv_union.byte_buf[7], conv_union.byte_buf[6], conv_union.byte_buf[5], conv_union.byte_buf[4], conv_union.byte_buf[3], conv_union.byte_buf[2], conv_union.byte_buf[1], conv_union.byte_buf[0]]; time_new := conv_union.lreal_val; // 找到报文头后退出循环,和Python逻辑一致 EXIT; END_IF; END_FOR;
如果需要优化性能,也可以提前把字节序反转封装成一个单独的函数,避免重复写反转逻辑。
内容的提问来源于stack exchange,提问作者Harry
相关产品推荐
相关产品推荐

