介紹一個使用邊緣閘道器分析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/,如需轉載,請註明出處,否則將追究法律責任。