愿所有在LabVIEW读取CAN方面的迷茫的人,重拾信心 |
真是太过分了,婶可忍叔叔也不能忍!
在目前的行业发展里,不太可能出现这样一个方案盲区,必然会有比较高效的读取办法的。
经过对比,我们最终选择了python,因为python做一些小功能模块的自动化,实在是太方便了,特别是大名鼎鼎的python-can库,简直是方便得不要不要的。
用LabVIEW的库,读取一个6M的blf文件,大约需要60秒,但是用python只需要3秒,效率提升20倍。
这可真是让人眼红啊,马克思都说了,如果有150%的利润,资本家就敢铤而走险,那这20倍的效率提升,实在是让人把持不住呀,师子一号估计也不能免俗,要沦陷了。
但是,还有个问题,无论是capl还是python还是LabVIEW,读取blf的时候,基本上都是读到内存里,很难串应用。
我们用python读,那基本上相关逻辑都是在python里做了。所以我们经常可以看到工程师用python处理CAN报文的时候,各种自定义txt记录格式,不规范。
并且python用来做大型测试系统,实在是有点勉为其难。
这该咋办呢?
非常好办,对只要有稍微的C语言基础或者数据结构基础,这个事情就很好解决。
我们用python读取之后,再写入成二进制文件,不就好了吗?
LabVIEW读取二进制文件,效率那可是杠杠的。
基本的思路是,定义一个二维数组,元素为U8,尺寸为N*80,N为报文帧数。每个报文用80个字节来存储,其中8个字节用来存储时间戳,64个字节用来存储数据区(兼容canfd),4个字节用来存储id,4个字节用来存储其他乱八七糟的属性信息。
存储成二进制文件之后,用labview读取完整的二进制内容,然后用强制数据转换,就可以直接转换成结构体数组啦,跟用LabVIEW直接读的效果是一样的,但是速度大大增加。
更过分的事
在面对更大尺寸的blf文件时,LabVIEW的blf库会更加拉胯,比如100M的blf文件,它可能需要1个小时,太尴尬了。
这种情况下,我们仍然可以用python进行二进制转存,而且为了防止转存出来的文件过大,在LabVIEW中出现内存不足的问题,我们可以在转存成二进制文件时,把它切割成1M左右的小的二进制文件,完全不影响后续的处理效率,串行读取效率更高。
下面讲一下详细的原理哈。
import can
f = "D:\\blfs\\2.blf"
log_data = can.BLFReader(f)
print("message count = ",log_data.object_count)
for message in log_data:
print(message)
message count = 8
Timestamp: 1726023012.618641 ID: 123 S Tx DL: 8 11 22 33 44 55 66 77 88 Channel: 0
Timestamp: 1726023013.053281 ID: 456 S Tx F DL: 16 01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01 Channel: 1
Timestamp: 1726023013.503856 ID: 123 S Tx DL: 8 11 22 33 44 55 66 77 88 Channel: 0
Timestamp: 1726023014.016656 ID: 456 S Tx F DL: 16 01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01 Channel: 1
Timestamp: 1726023014.436349 ID: 123 S Tx DL: 8 11 22 33 44 55 66 77 88 Channel: 0
Timestamp: 1726023014.902429 ID: 456 S Tx F DL: 16 01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01 Channel: 1
Timestamp: 1726023015.337538 ID: 123 S Tx DL: 8 11 22 33 44 55 66 77 88 Channel: 0
Timestamp: 1726023015.741603 ID: 456 S Tx F DL: 16 01 02 03 04 05 06 07 08 08 07 06 05 04 03 02 01 Channel: 1
Process finished with exit code 0
我们要发挥想象力了。
代码如下所示:
import can
import struct
import numpy as np
f = "D:\\blfs\\2.blf"
log_data = can.BLFReader(f)
print("message count = ",log_data.object_count)
data_arr = (struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0) +
struct.pack('i', 0))
python_arr = [struct.pack('d', obj.timestamp) +
struct.pack('i', obj.arbitration_id) +
struct.pack('i', obj.channel)[0:1] +
struct.pack('i', obj.dlc)[0:1] +
struct.pack('i', obj.is_rx)[0:1] +
struct.pack('i', obj.is_fd)[0:1] +
obj.data +
data_arr[len(obj.data):] for obj in log_data]
arr = np.array(python_arr)
binary1 = arr.tobytes()
print(binary1)
with open("D:\\blfs\\2-ok.blf", 'wb') as f:
f.write(binary1)
下面我们来到LabVIEW中,展示如何处理:
1、如下图所示,python封装的结构体,包含了5+1总共6个元素,其中前5个分别为id、channel、dlc、is_rx、is_fd,第六个为64字节的u8数组(有效数据靠前存储,后面放默认值填充)。
struct.pack('d', obj.timestamp) +
struct.pack('i', obj.arbitration_id) +
struct.pack('i', obj.channel)[0:1] +
struct.pack('i', obj.dlc)[0:1] +
struct.pack('i', obj.is_rx)[0:1] +
struct.pack('i', obj.is_fd)[0:1
3、data要根据dlc的值,在最后的64个字节中进行截断读取。之所以这么做,是为了内存对齐,进一步提升处理速度。
通过上述方法,我们就实现了python和LabVIEW的联合,发挥各自的优势,实现了对blf文件的高效处理。
请相信师子一号,这是目前全行业所能想到的性价比最高、最省钱、可扩展最简单的办法了。
我们这么折腾,绝对不是脱了裤子放气,事实上,对于一个100M的blf文件,这两个环节加一起所消耗的时间,也不到1分钟,完全可以接受了。
当然,还需要说明的是,二进制文件大约比blf文件的体积大7倍左右,但是鉴于二进制文件的临时性,我们在做完分析之后,可以直接将其删除。
至于文章前面所说的分割成1M的二进制文件,其办法也很简单,在python的for循环中判断一下循环索引%N是否为0即可,为0则做一次保存,并初始化数组。N的值随便定,如果定为100000的话,二进制文件大约就是6M,读取也很快。
这种情况下,你完全不用等python分割完,就可以开始进行LabVIEW读取和逻辑处理,会更加节省时间。
总线10讲,东半球最好用的excel2dbc工具,永远免费送
【课程】汽车和LabVIEW完美结合,干货十足,助您掌握核心技术,提升职场竞争力
专题技术交流群,用户讨论组,大合集(加各种工具交流群,请后台联系)