使用邊緣計算閘道器分析CAN報文

qwer1030274531發表於2021-01-26

介紹一個使用邊緣閘道器分析CAN報文,並將其進行資料視覺化的應用案例。

硬體介紹

在此應用案例中,使用的感測器是一個 加速度感測器,可以輸出x、y、z軸三週的加速度。 感測器的通訊協議是CAN Open。
使用的閘道器是虹科 Dynagate 10-12

感測器資訊收集

首先,使用閘道器Dynagate 10-12 收集CAN報文。在此之前,需要設定好閘道器的CAN介面。這裡開放我們的can0介面,並且設定好波特率,與我們的感測器匹配。本次案例的感測器波特率是 1000Mpbs

ip link set can0 down
ip link set can0 type can bitrate 1000000
ip link set can0 up123

設定好之後,使用命令獲取can報文

candump can01

就會得到原始的 raw_data
在這裡插入圖片描述
首先是CAN id, 其次是dlc, 最後是CAN報文內容。

使用python處理CAN 報文

有了 raw data, 還需要有DBC檔案對CAN報文進行解析。我們這裡使用python 匯入dbc檔案,並且進行解析

import datetime#  匯入兩個python處理can匯流排的包import canimport cantools#  dbc檔案路徑DBC_DIR = "/home/hkaco/demo.dbc"#  載入dbc檔案 並建立can匯流排例項db = cantools.database.load_file(DBC_DIR)can_bus = can.interface.Bus('can0', bustype = 'socketcan')def main():
	while (1):
		#  迴圈獲取can匯流排的資料
		msg = can_bus.recv()
		#  獲取訊息並解碼
		recv = db.decode_message(msg.arbitration_id, msg.data)
		timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
		print(timestamp)
		print(recv)
		if __name__ == "__main__":
	main()12345678910111213141516171819202122232425

透過我們的解析,得到的結果如下圖所示:
在這裡插入圖片描述
可以看到,我們成功的使用dbc檔案把獲取到的raw data解析成了我們能夠理解的CAN報文。

將獲取到的CAN資料透過UDP協議傳送到PC端實現資料視覺化

由於邊緣閘道器通常是不帶顯示裝置的,所以我們如果想要直觀的看到這個資料產生的結果,可以透過udp協議將閘道器解析的結果傳送到pc端,然後pc端使用matplotlib等資料處理、資料視覺化庫即可完成

那麼首先是在閘道器中寫好傳送的指令碼,我們只需要在剛剛的指令碼中,新增udp傳送的相關程式碼即可。

import socketimport jsonimport time#  匯入兩個python處理can匯流排的包import canimport cantools#  dbc檔案路徑DBC_DIR = "/home/hkaco/demo.dbc"#  目標ip地址和目標埠,ip地址DEST_IP = "192.168.189.201"  DEST_PORT = 6789#  定義一個透過udp協議傳送函式def send_msg(udp_socket, message):
	udp_socket.sendto(message, (DEST_IP, DEST_PORT))#  載入dbc檔案 並建立can匯流排例項db = cantools.database.load_file(DBC_DIR)can_bus = can.interface.Bus('can0', bustype = 'socketcan')def main():
	
	udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	while (1):
		#  迴圈獲取can匯流排的資料
		msg = can_bus.recv()
		#  獲取訊息並解碼
		recv = db.decode_message(msg.arbitration_id, msg.data)
		#  專為字典格式
		recv = json.dumps(recv)
		send_msg(udp_socket, bytes(recv, encoding="utf-8"))
		time.sleep(0.5)
		
	udp_socket.close()
		if __name__ == "__main__":
	main()12345678910111213141516171819202122232425262728293031323334353637383940

傳送端寫好了之後,我們在PC端寫好還要寫好接收端程式碼,並完善資料視覺化程式碼

import socketimport matplotlib.pyplot as pltimport timeimport datetimeimport jsonfrom datetime import datetimedef recv_msg(udp_socket):
    msg = udp_socket.recvfrom(1024)
    # 解碼
    recv_ip = msg[1]
    recv_message = msg[0].decode('utf-8')
    recv_dict = json.loads(recv_message)
    #  recv_dict是字典,可以使用鍵取值
    x = recv_dict['Acc_X']
    y = recv_dict['Acc_Y']
    z = recv_dict['Acc_Z']
    t = recv_dict['T']
    return x, y, z, tdef main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(('', 6789))
    
    font1 = {'family' : 'Times New Roman',  
    'weight' : 'normal',  
    'size'   : 9,  
    } 
    plt.rcParams['font.sans-serif']=['SimHei']
    
    plt.rcParams['axes.unicode_minus']=False
    plt.ion()
    timel = []
    xl = []
    yl = []
    zl = []
    tl = []
    while True:
        nowtime = datetime.utcnow().strftime("%H:%M:%S")
        x, y, z, t = recv_msg(udp_socket)
        xl.append(x)
        yl.append(y)
        zl.append(z)
        tl.append(t)
        timel.append(nowtime)
        plt.clf()
        plt.subplots_adjust(hspace=0.5)
        ax1 = plt.subplot(211)
        ax1.plot(timel, xl, c="b", label='x')
        ax1.plot(timel, yl, c="r", label='y')
        ax1.plot(timel, zl, c= "y", label='z')
        plt.legend(loc='upper right', prop=font1, frameon=False)
        plt.xticks(rotation = 270)
        plt.xlabel('時間戳')
        plt.ylabel('加速度值')
        ax2 = plt.subplot(212, sharex = ax1)
        ax2.plot(timel, tl, c="c", label='T')
        plt.xticks(rotation = 270)
        plt.xlabel('時間戳')
        plt.ylabel('T')
        plt.legend(loc='upper right', prop=font1, frameon=False)
        plt.pause(0.001)
        plt.ioff()
    socket.close()if __name__ == "__main__":
    main()1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980

最終結果 /oldage/

首先執行接收端,然後在我們的邊緣閘道器Dynagate 10-12中執行傳送端。結果如圖所示:
在這裡插入圖片描述


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30239065/viewspace-2752884/,如需轉載,請註明出處,否則將追究法律責任。

相關文章